eslint-plugin-tailwind-design-tokens
v0.3.0
Published
ESLint plugin that flags hardcoded colors and default Tailwind palette classes, steering you toward your design-system tokens.
Maintainers
Readme
eslint-plugin-tailwind-design-tokens
ESLint plugin that flags hardcoded colors and default Tailwind palette classes, steering you toward your design-system tokens.
Why
A design system defines a finite color palette as tokens — --color-ink, bg-primary,
text-soft-green. But nothing stops a raw #0a0a0a, an rgb(10 10 10), or a stock text-red-500
from sneaking into a component, and every one of those quietly erodes the system. This plugin
catches them at lint time and, when the hardcoded value matches one of your tokens, tells you exactly
which token to use instead.
It understands where tokens live across Tailwind versions — a v4 @theme block, a v3
tailwind.config.js, or an inline map — so it works whatever your setup.
Before / after
// ✗ flagged — stock palette class + hardcoded hex
<button className="bg-[#0a0a0a] text-red-500" />;
// ✓ design-system tokens
// (when #0a0a0a maps to a token, bg-[#0a0a0a] → bg-ink is auto-fixable)
<button className="bg-ink text-primary" />;Install
npm install --save-dev eslint-plugin-tailwind-design-tokens
# or
yarn add --dev eslint-plugin-tailwind-design-tokens
# or
pnpm add --save-dev eslint-plugin-tailwind-design-tokensRequires ESLint 9+ (both the legacy .eslintrc and the flat config systems are supported).
Every release is published from CI with npm provenance attestations, so each version on npm links back to the exact commit and workflow that built it.
Usage
Flat config (ESLint 9+, eslint.config.mjs)
Quick start with the recommended config:
import tailwindDesignTokens from 'eslint-plugin-tailwind-design-tokens';
export default [...tailwindDesignTokens.configs['flat/recommended']];Recommended turns both rules on as errors. To get token suggestions (not just "hardcoded color"
warnings), point no-hardcoded-colors at your token source:
import tailwindDesignTokens from 'eslint-plugin-tailwind-design-tokens';
export default [
{
plugins: { 'tailwind-design-tokens': tailwindDesignTokens },
rules: {
'tailwind-design-tokens/no-default-palette': 'error',
'tailwind-design-tokens/no-hardcoded-colors': [
'error',
{ cssFile: './src/styles/globals.css' },
],
},
},
];Legacy config (.eslintrc.json)
{
"plugins": ["tailwind-design-tokens"],
"extends": ["plugin:tailwind-design-tokens/recommended"]
}Or configure the rules directly to add a token source:
{
"plugins": ["tailwind-design-tokens"],
"rules": {
"tailwind-design-tokens/no-default-palette": "error",
"tailwind-design-tokens/no-hardcoded-colors": [
"error",
{ "cssFile": "./src/styles/globals.css" }
]
}
}Rules
💼 Configurations enabled in.
✅ Set in the recommended configuration.
🔧 Automatically fixable by the --fix CLI option.
💡 Manually fixable by editor suggestions.
| Name | Description | 💼 | 🔧 | 💡 | | :------------------------------------------------------- | :----------------------------------------------------------------------------------------------------- | :-- | :-- | :-- | | no-default-palette | Disallow default Tailwind palette colors; use design-system tokens | ✅ | | | | no-hardcoded-colors | Disallow hardcoded color values (hex, rgb, hsl, hwb, lab, lch, oklab, oklch); use design-system tokens | ✅ | 🔧 | 💡 |
Configuring tokens
no-hardcoded-colors can read your design tokens from any combination of these sources (later
sources win on conflict: cssFile < configFile < tokens):
| Option | Tailwind | What it reads |
| ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| cssFile | v4 | --color-* declarations inside the @theme { … } block of the given CSS file. |
| configFile | v3 | theme.colors / theme.extend.colors from a tailwind.config.js (nested palettes are flattened, e.g. brand-500; a DEFAULT key maps to the bare name). |
| tokens | any | An inline { "<color>": "<token-name>" } map — for projects whose tokens live outside Tailwind. |
'tailwind-design-tokens/no-hardcoded-colors': ['error', {
cssFile: './src/styles/globals.css', // Tailwind v4 @theme
configFile: './tailwind.config.js', // Tailwind v3
tokens: { '#0a0a0a': 'ink' }, // inline / non-Tailwind
allow: ['transparent', '#ffffff'], // colors to ignore
}]Color values are normalized before matching, so #FFF in your code matches a token defined as
#ffffff. Hex and the CSS color functions rgb(), hsl(), hwb(), lab(), lch(), oklab(),
and oklch() are all detected, including inside Tailwind arbitrary values like bg-[#0a0a0a].
How it works
no-hardcoded-colorsscans every string literal and template-literal quasi for color values, normalizes each, and looks it up in your token map. A match reports "use the design token X"; no match reports "unexpected hardcoded color".no-default-palettesplits class strings and flags any default Tailwind palette utility (prefix-family-shade), tolerating important (!) and opacity (/50) modifiers.
Token files are read once and cached per ESLint process, invalidated by file mtime.
Contributing
Issues and PRs welcome — see CONTRIBUTING.md for setup, the test/doc workflow, and commit conventions. Quick start:
npm install
npm test # vitest
npm run lint
npm run typecheck
npm run buildLicense
MIT © Konstantinos Mavrikas
