Skip to main content

Linting with stylelint

Griffel compiles makeStyles() and makeResetStyles() calls to atomic CSS ahead of time. That CSS is never written to a .css file, so a CSS linter has nothing to read and mistakes like an unmatchable selector stay unnoticed until runtime.

@griffel/postcss-syntax is a PostCSS custom syntax that runs the Griffel transform over your style files and hands the generated CSS to stylelint, with source locations pointing back to the original TypeScript.

Install​

yarn add --dev stylelint @griffel/postcss-syntax

Setup​

Point stylelint's customSyntax at the package:

.stylelintrc.json
{
"customSyntax": "@griffel/postcss-syntax",
"rules": {
"selector-anb-no-unmatchable": true
}
}

Then lint your style files:

npx stylelint "src/**/*.styles.ts"
caution

@griffel/postcss-syntax is ESM only. If your project is CommonJS, use stylelint.config.mjs instead of .stylelintrc.js, as the latter is loaded with require().

Example​

example.styles.ts
import { makeStyles } from '@griffel/react';

export const useStyles = makeStyles({
root: {
':nth-child(0)': { color: 'red' },
},
});

:nth-child(0) matches nothing, so stylelint reports selector-anb-no-unmatchable and points at the root slot in example.styles.ts rather than at generated CSS.

Disabling rules​

stylelint-disable comments cannot be placed in generated CSS. Use a griffel-csslint-disable line comment above a slot instead:

export const useStyles = makeStyles({
// griffel-csslint-disable selector-anb-no-unmatchable
root: {
':nth-child(0)': { color: 'red' },
},
});

For makeResetStyles() place the directive above the declaration:

// griffel-csslint-disable selector-anb-no-unmatchable
export const useResetStyles = makeResetStyles({
':nth-child(0)': { color: 'red' },
});

Each directive disables exactly one rule, repeat the comment to disable several.

Linting custom wrappers​

By default only imports from @griffel/core, @griffel/react and @fluentui/react-components are processed. If your project re-exports Griffel from its own package, build a configured syntax with createSyntax():

stylelint.config.mjs
import { createSyntax } from '@griffel/postcss-syntax';

export default {
customSyntax: createSyntax({
importsToTransform: ['@griffel/react', '@myScope/griffel'],
}),
rules: {
'selector-anb-no-unmatchable': true,
},
};
caution

importsToTransform replaces the default list rather than extending it, keep @griffel/react in it if you also import from it directly.

Limitations​

  • Styles must be statically evaluable, see Limitations.
  • stylelint's --fix is not supported, as generated CSS cannot be mapped back to the original JavaScript accurately enough to rewrite it.