Agentic Workflows

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.


The recommended config enables the canonical rule set:

import css from '@master/eslint-config-css'export default [...css]
RuleDefaultFixablePurpose
@master/css/sort-classeswarnYesSort classes into a stable generated-rule order.
@master/css/no-invalid-classeserrorNoReport invalid Master CSS syntax and invalid generated CSS.
@master/css/no-conflicting-classeswarnYesReport full and partial declaration conflicts in the same variant scope.
@master/css/prefer-canonical-classeswarnYesPrefer 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:lg

Variants 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@dark

Sorting also removes duplicate class values in the same class string.

inline-flex px:md inline-flexinline-flex px:md

Ordering 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:md

It 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-60

Related 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:md

Condition 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@dark

The 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.

OptionDefaultEffect
preferStaticUtilitiestruePrefer named or semantic utilities such as text-center over native declaration forms.
preferThemeTokenstruePrefer theme token values such as font:md over equivalent raw values.
preferPropertyAliasestruePrefer shorter property aliases such as m:md over margin:md.
preferVariableReferencestruePrefer token keys such as fg:red-60 over direct references such as fg:var(--color-red-60).
preferMultiValueTokenstruePrefer tokenized multi-value forms such as `m:md
preferCompositionUtilitiestruePrefer composed utilities such as size:md over equivalent w:md h:md pairs.
preferConditionOrdertruePrefer stable condition suffix order such as @sm@dark over @dark@sm.
preferNativeDeclarationsInComposetruePrefer native declarations over declaration-like classes inside CSS @compose.
preferVariantBlocksInComposetruePrefer @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@md

When 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:lg
b-solid bt-dashedbr-solid bb-solid bl-solid bt-dashed

Supported sources

The default config checks class strings in common markup, JavaScript locations, and unquoted @compose class lists in parsed CSS/style sources.

SettingDefaultUse
classAttributes['class', 'className']Markup attributes that contain class strings.
classFunctionsclsx, 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:#123456

Unexpected 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.



  • Master UI


© 2026 Aoyue Design LLC.MIT License
Trademark Policy