Code Linting for Master CSS
An ESLint integration for enforcing team coding styles, making your template markup more organized, and catching syntax errors early.
Overview
Code linting validates Master CSS class strings where they are authored: markup attributes, framework templates, JavaScript utility calls, and configured class declarations. The ESLint integration resolves the active project manifest, then checks each class against Master CSS syntax, generated CSS declarations, and team policy.
Use the installation integrations to add the recommended config to a project. Use Visual Studio Code setup when you want the VS Code ESLint extension to surface class policy diagnostics and apply sort-on-save.
The Master CSS VS Code extension and the VS Code ESLint extension are complementary. Master CSS provides completion, hover, color tools, highlighting, directive diagnostics, manifest diagnostics, and directive formatting. ESLint provides sort-classes, prefer-canonical-classes, no-conflicting-classes, no-invalid-classes, and opt-in raw-value policy diagnostics, so the Master CSS extension does not duplicate these warnings by default.
For scripts, CI probes, and other tools that need a Master CSS native machine interface without loading an ESLint parser stack, use npx @master/css-cli lint --format json. Treat it as a preflight diagnostics surface; keep eslint . as the normal human development and CI lint command for JavaScript and framework projects.
When an AI client supports tool calls, the Master CSS MCP server can run the same lint policy through mastercss_lint_project and preview safe fixes. ESLint should still remain the default human development and CI lint workflow for JavaScript and framework projects.
Use npx @master/css-cli inspect --format json when the tool needs scanner state, stylesheet entry metadata, generated CSS size, or explicit missing CSS checks. inspect is not a replacement for lint policy rules such as class sorting, canonical classes, conflicts, or raw-value policy.
Install the recommended config
The recommended config enables the canonical rule set:
import css from '@master/eslint-config-css'export default [...css]| Rule | Default | Fixable | Purpose |
|---|---|---|---|
@master/css/sort-classes | warn | Yes | Sort classes into a stable generated-rule order. |
@master/css/no-invalid-classes | error | No | Report invalid Master CSS syntax and invalid generated CSS. |
@master/css/no-conflicting-classes | warn | Yes | Report full and partial declaration conflicts in the same variant scope. |
@master/css/prefer-canonical-classes | warn | Yes | Prefer semantic utilities, theme tokens, property aliases, composition utilities, and condition order. |
Linting rules
Sort classes
@master/css/sort-classes keeps class strings stable and reviewable. It sorts known Master CSS classes before unknown classes, follows generated layer and condition priority, and groups base classes by their generated CSS intent: position and layout, size, spacing, box, typography, paint, and effects.
bg:white font:md flex px:4x rel w:full shadow:lg rounded z:10 gap:2xrel z:10 flex gap:2x w:full px:4x rounded font:md bg:white shadow:lgVariants such as :hover, @dark, and @sm stay after the base class body in generated condition order.
bg:black:hover flex p:2x w:full block@dark text-centerflex w:full p:2x text-center bg:black:hover block@darkSorting also removes duplicate class values in the same class string.
inline-flex px:md inline-flexinline-flex px:mdOrdering is a formatting policy. It does not change generated CSS, but it makes class strings easier to review and keeps automated fixes deterministic across frameworks and editors.
No invalid classes
@master/css/no-invalid-classes reports classes that match Master CSS syntax but generate invalid CSS.
<button class="font:">...</button>Invalid value for font property.
By default, unmatched classes are ignored so teams can mix Master CSS with existing global classes during migration.
Enable disallowUnknownClass when the project should only use classes known to the active Master CSS manifest:
export default [ { rules: { '@master/css/no-invalid-classes': ['error', { disallowUnknownClass: true }] } }]<button class="btn">...</button>"btn" is not a valid or known class.
Define project classes in the CSS entry when they are intentional:
@components { btn { @compose inline-flex px:md; }}Prefer canonical classes
@master/css/prefer-canonical-classes keeps committed classes close to the project vocabulary.
text-align:center font:16px margin:mdtext-center font:md m:mdIt also canonicalizes multi-value tokens and direct CSS variable references when every value maps to the active theme:
m:1rem|1.5rem fg:var(--color-red-60)m:md|lg fg:red-60Related size and spacing pairs can be composed into shorter utilities:
w:md h:md mt:md mb:md padding-left:1rem padding-right:1remsize:md my:md px:mdCondition suffixes are kept in a stable order for safe breakpoint and mode combinations:
block@dark@sm font:16px@dark@sm mt:md@dark@sm mb:md@dark@smblock@sm@dark font:md@sm@dark my:md@sm@darkThe same fixes apply inside unquoted @compose class lists when ESLint is running on a parsed CSS or style source:
.btn { @compose text-align:center contain:content bg:blue-60:hover@sm; @compose text-center; contain: content; @variant :hover@sm { @compose bg:blue-60; } }Standalone CSS files are checked by the default @master/eslint-config-css export:
import css from '@master/eslint-config-css'export default [...css]Framework files with parsed <style> blocks, such as Vue and Svelte files, can lint @compose in those style blocks through the normal framework parser setup.
| Option | Default | Effect |
|---|---|---|
preferStaticUtilities | true | Prefer named or semantic utilities such as text-center over native declaration forms. |
preferThemeTokens | true | Prefer theme token values such as font:md over equivalent raw values. |
preferPropertyAliases | true | Prefer shorter property aliases such as m:md over margin:md. |
preferVariableReferences | true | Prefer token keys such as fg:red-60 over direct references such as fg:var(--color-red-60). |
preferMultiValueTokens | true | Prefer tokenized multi-value forms such as `m:md |
preferCompositionUtilities | true | Prefer composed utilities such as size:md over equivalent w:md h:md pairs. |
preferConditionOrder | true | Prefer stable condition suffix order such as @sm@dark over @dark@sm. |
preferNativeDeclarationsInCompose | true | Prefer native declarations over declaration-like classes inside CSS @compose. |
preferVariantBlocksInCompose | true | Prefer @variant, @dark, and @light blocks over suffixes inside CSS @compose. |
Disable one family when a team wants a more literal authoring style:
export default [ { rules: { '@master/css/prefer-canonical-classes': ['warn', { preferStaticUtilities: true, preferThemeTokens: true, preferPropertyAliases: false }] } }]No conflicting classes
@master/css/no-conflicting-classes reports classes that emit the same declaration properties in the same variant scope.
m:0.625rem m:5xm:5x"m:0.625rem" is overridden by "m:5x".
Variant scope matters. Classes with different selectors, modes, or at-rules do not conflict with each other.
m:10x@sm m:3.125rem@mdWhen a conflict can be fixed automatically, the rule removes the earlier overridden class and keeps the later class. Review the fix if the authoring order was carrying intent.
Partially overlapping spacing, physical inset, radius, and border width/color/style shorthands are split so the surviving declarations are kept:
mx:md ml:lgmr:md ml:lgb-solid bt-dashedbr-solid bb-solid bl-solid bt-dashedSupported sources
The default config checks class strings in common markup, JavaScript locations, and unquoted @compose class lists in parsed CSS/style sources.
| Setting | Default | Use |
|---|---|---|
classAttributes | ['class', 'className'] | Markup attributes that contain class strings. |
classFunctions | clsx, cva, ctl, cv, classnames, styled, classList.* | JavaScript callees whose arguments can contain class strings. |
classDeclarations | [] | Project-specific variables or object properties that should be treated as class declarations. |
ignoredKeys | ['compoundVariants', 'defaultVariants'] | Object keys ignored while traversing variant config objects. |
Customize settings under the @master/css settings key:
export default [ { settings: { '@master/css': { classAttributes: ['class', 'className', 'containerClass'], classFunctions: ['clsx', 'cva'], classDeclarations: ['classes'] } } }]Team policy
Use the recommended config for most projects:
import css from '@master/eslint-config-css'export default [...css]Use stricter validation when the team wants every class to come from Master CSS syntax or the project manifest:
export default [ ...css, { rules: { '@master/css/no-invalid-classes': ['error', { disallowUnknownClass: true }] } }]Customize canonicalization when a team wants to keep one class family literal while still applying the other recommendations:
export default [ ...css, { rules: { '@master/css/prefer-canonical-classes': ['warn', { preferStaticUtilities: true, preferThemeTokens: true, preferPropertyAliases: false }] } }]Enable raw value policy when the team wants token-backed utilities to use tokens unless a value is explicitly allowed:
export default [ ...css, { rules: { '@master/css/no-unapproved-raw-values': ['warn', { allowProperties: ['width', 'height'], allowedPatterns: ['^var\\(', '^calc\\('] }] } }]font:15px m:17px fg:#123456Unexpected raw value "15px" in "font:15px". Use a token or allow it explicitly.
Use editor sort-on-save for low-friction cleanup:
{ "eslint.codeActionsOnSave.rules": [ "@master/css/sort-classes" ]}See Visual Studio Code setup for the full editor flow.
Setup links
- Installation integrations for framework setup.
- Visual Studio Code setup for editor diagnostics and sort-on-save.
Use manifest-aware editor intelligence for Master CSS classes, directives, project tokens, generated CSS previews, colors, and workspace-specific configuration.
Use AI coding agents to write, review, and validate Master CSS classes with project context, prompts, linting, and visual checks.