Editor Setup
Maple has no build step and no configuration file, so there is nothing for an editor to read in order to understand your classes. The official Maple CSS extension closes that gap by running the same engine your page runs, so autocomplete, hover help, diagnostics, and color swatches reflect the exact CSS Maple would generate at runtime.
Installation
Search for Maple CSS in the Extensions view, or install it from the command line:
code --install-extension f12io.maple-vscode-extensionEvery release is published to both the Visual Studio Marketplace and Open VSX, so editors that cannot reach the Microsoft marketplace, such as Cursor, Windsurf, and Antigravity, install the same extension from their own registry.
Enabling the Extension
The extension stays inactive by default so it never interferes with projects that do not use Maple. There is one exception: an HTML file that loads maple.js or maple.min.js from its <head> activates the extension for that file automatically, which covers the Quick Start setup without any configuration.
For every other project layout, turn it on explicitly for the workspace:
.vscode/settings.json
{
"maple.enabled": true
}
Setting maple.enabled to false is not the same as leaving it unset. An explicit false disables the extension everywhere, including HTML files that would otherwise activate it on their own.
Features
Each feature can be toggled independently, so you can keep the parts that help and drop the ones that do not fit your workflow.
Suggests utilities, values, shades, and the custom aliases found in your workspace as you type.
features.autoCompleteShows the formatted CSS a class generates, so you can verify a utility without opening DevTools.
features.hoverHelpRenders a live swatch next to any color utility and opens the native VS Code picker on click.
features.colorPicker Warns about invalid classes, out-of-range shades, a misplaced ! prefix, alias definitions outside the <html> element, and utilities that conflict with each other.
features.diagnosticsColors the parts of a class separately, so media queries, selectors, operators, utilities, and values stay readable in long class strings.
features.highlighting Custom aliases are discovered by scanning the workspace for --alias- definitions, so an alias you declare on the <html> element of one file is suggested and documented in every other file of the same workspace. See Aliases for the definition syntax.
Settings
All options live under the maple namespace and can be set in the settings UI or directly in settings.json.
enabledfalseMaster switch for the current workspace. Leave it unset to keep the automatic HTML activation.
excludenode_modules, .gitGlob patterns for files where every feature is turned off.
features.autoCompletetrueToggles suggestions.
features.hoverHelptrueToggles CSS hover tooltips.
features.colorPickertrueToggles swatches and the color picker.
features.diagnosticstrueToggles linting and conflict warnings.
format.enabledfalseEnables the built-in class formatter and its command.
format.onSavefalse Formats Maple classes on save. Requires format.enabled.
format.maxClassesPerLine4 Classes allowed on a single line before wrapping. Set to 1 to force one class per line.
.vscode/settings.json
{
"maple.enabled": true,
"maple.exclude": ["**/node_modules/**", "**/.git/**"],
"maple.features.autoComplete": true,
"maple.features.hoverHelp": true,
"maple.features.colorPicker": true,
"maple.features.diagnostics": true,
"maple.features.highlighting": "on",
"maple.format.enabled": true,
"maple.format.onSave": true,
"maple.format.maxClassesPerLine": 4
}
Highlighting Modes
A Maple class carries more structure than a plain class name, and the three highlighting modes decide how much of that structure is colored.
"on"Every token gets its own color: media queries, parent, self, and child selectors, operators, separators, utilities, values, aliases, variables, and the important prefix.
"minimal"Utilities, values, and aliases share a single color, while structural tokens such as media queries, selectors, and operators keep theirs. This keeps the shape of a class visible without turning the line into a rainbow.
"off"No Maple coloring. Your theme renders class attributes as it normally would.
Formatting Classes
Utility classes grow long, and a single line of thirty utilities is hard to scan. The Maple formatter only adds line breaks. It never reorders, adds, or removes a class, so the class string means exactly the same thing before and after a format pass.
A break is inserted where the property type changes from one class to the next, and again whenever a line reaches maxClassesPerLine. Classes stay in the order you wrote them, so this reads as grouping only where you already placed related utilities together. If a break would strand a single class on its own line, it is folded back into the neighbouring line.
<div
class="
c-blue p-2 m-2 fs-50
o-50 fw-normal
"
></div>
Two layout rules apply on top of the per-line limit:
The
htmlelement gets one class per line once it goes over the limit. Its classes are alias definitions, which read poorly side by side. At or under the limit it stays on a single line like any other element.<html class=" --alias-btn=bgc-red-500;p-2 --alias-card=p-{space,4} --alias-underline=brb;brc-{color,body}-90 --alias-square=px-{space,1.5};ar=1 --alias-prose=fs-50;lh-1.6 " ></html>A blank line is how you group classes yourself. The formatter never moves a class across one, so anything you separate stays separated, pass after pass.
<html class=" --ff-main='Inter',-apple-system,BlinkMacSystemFont,sans-serif --ff-mono='JetBrains_Mono',monospace --color-body=oklch(0.560_0.025_260) --color-accent=oklch(0.660_0.25_260) --color-calm=oklch(0.660_0.15_235) --color-safe=oklch(0.630_0.2_150) --color-attention=oklch(0.660_0.25_80) --color-critical=oklch(0.660_0.2_20) @dark:--l-shift=-0.7 --alias-space-none=mt-0 --alias-space-sm=mt-2 --alias-space-md=mt-4 --alias-space-lg=mt-8 " > </html>
Enabling the Formatter
Set maple.format.enabled to true to register the Maple CSS: Format Classes command, which formats the active document on demand. Add maple.format.onSave if you want the same pass to run every time you save.
The extension does not register itself as a document formatter, so it never competes for the editor.defaultFormatter slot. It formats through the command and through its own save hook, which means it runs in addition to whatever formatter your editor already uses on save.
Prettier Without the Maple Plugin
editor.formatOnSave enabled, both formatters run on the same save and undo each other, which shows up as flickering. Installing the Prettier plugin below resolves this, because Prettier then produces the same layout as the extension and the two agree on the result. Prettier Plugin
@f12io/prettier-plugin-maple applies the same layout from inside Prettier's own pass. It shares the formatting logic with the extension, so editors, pre-commit hooks, and CI pipelines all produce identical output.
npm install --save-dev prettier @f12io/prettier-plugin-maple.prettierrc
{
"plugins": ["@f12io/prettier-plugin-maple"],
"mapleMaxClassesPerLine": 4
}
The plugin wraps the html, vue, angular, babel, babel-ts, and typescript parsers. It formats class attributes in templates, className expressions in JSX including ternaries, the arguments of clsx, classNames, and cva, and any expression you opt in with a /* maple */ comment. Hosts that cannot contain multi-line strings, such as Vue :class and Angular [ngClass], are normalized on a single line instead.
Comment Directives
Directives are comments you place in the code itself. They control the extension where a workspace setting would be too broad, for example a generated file that should be ignored or a string that Maple cannot recognize as a class list on its own.
/* maple-disable-file */Disables the extension for the entire file.
/* maple-disable-line */Disables the current line. Place it at the end of that line.
/* maple-disable-next-line */Disables the line that immediately follows.
/* maple-disable */Disables every feature for the rest of the file, until a matching enable directive.
/* maple-enable */Re-enables the features after a disable directive.
/* maple */Opts the following expression in. Every string literal in it, including ternary arms, concatenation parts, template literals, and interpolated strings, is parsed as Maple classes until the statement ends. Objects opt in their keys.
/* maple-disable-next-line */
const legacy = 'p-4 not-a-maple-class';
// Opt in a template literal
const styles = /* maple */ `bgc-red-500 p-4`;
// Opt in both arms of a ternary
const state = /* maple */ isActive ? 'bgc-red-500 p-4' : 'bgc-gray-300 p-2';
Supported Languages
Class extraction is language aware, so the extension knows where a class list can appear in each of these file types:
- HTML:
.html - React:
.jsx,.tsx - Vue:
.vue - Svelte:
.svelte - Razor:
.razor,.cshtml - PHP:
.php - Twig:
.twig - JavaScript and TypeScript:
.js,.ts
In every one of them, the extension reads class and className attributes, plus any expression you opt in with /* maple */. Templates add their own framework syntax on top, and JavaScript and TypeScript files also pick up the arguments of clsx, classNames, and cva calls, which is what makes plain .ts files useful without a template around them.
Virtual Workspaces
Troubleshooting
If a feature stops responding, work through the checks below before filing a report:
- Confirm the extension is active for the file. Either
maple.enabledistrue, or the file is HTML and loads Maple from its<head>. - Check that the file is not matched by
maple.excludeand does not contain a disable directive. - Open
View → Output → Maple CSSto see the errors the extension logged.
Include that output when filing an issue.