Skip to content

design-no-unknown-token

Field Value
Tool ESLint
Enable via design() factory
Rule ID house-rules/design-no-unknown-token
Type problem
Autofix no
Source packages/rules/src/design-no-unknown-token.mjs
Docs packages/rules/docs/design-no-unknown-token.md

var(--name) with no definition.

Require every var(–name) to resolve to a custom property defined in a token file or in the same file.

  • unknown: var({{name}}) has no definition in the token files or in this file.
[
{
"tokenFiles": [],
"allow": []
}
]

From packages/rules/docs/design-no-unknown-token.md.

Rule ID: house-rules/design-no-unknown-token

The rule runs on the @eslint/css language. It reports a var(--name) whose name has no definition in the token files or in the linted file. Use the @house-rules/rules/design factory to enable it.

.card { border-color: var(--line); } /* passes: defined in the token file */
.card { border-color: var(--line-softer); } /* reported */
.chart { --bar-bg: var(--pop); background: var(--bar-bg); } /* passes: defined in this file */

The message is var(--line-softer) has no definition in the token files or in this file.

A misspelled or renamed token fails silently in the browser: the property falls back to its initial value and nothing warns you. This rule makes that a lint error.

It finds every var() in every declaration value. That includes custom-property values and var() calls nested in a fallback, such as var(--a, var(--b)). A name resolves when:

  • a token file defines it, in any selector or at-rule, or
  • the linted file defines it as a custom property anywhere, before or after the use, or
  • the linted file registers it with @property --name, or
  • it matches the allow option.
type Options = [
{
tokenFiles?: string[]; // default: []
allow?: string[]; // default: []
},
];
  • tokenFiles: CSS files that define the tokens, relative to ESLint’s working directory. design() fills this from its own tokenFiles. A missing file stops the lint with an error. With no token files, only same-file definitions count.
  • allow: names that need no definition, such as a property that JavaScript sets at run time. An entry written as /pattern/flags is a regular expression; any other entry must match the whole name.

/pattern/ entries are trusted repo config. They are compiled as written, the same way ESLint core options such as id-match treat a pattern. The rule does not check them for safety. A pattern that backtracks badly will slow the lint down.

design({
tokenFiles: ["src/styles/tokens.css"],
rules: { "design-no-unknown-token": { allow: ["--bar", "/^--radix-/"] } },
});
  • Definitions in other stylesheets that are not token files do not count. A custom property shared between two component files belongs in a token file.
  • var() inside at-rule preludes is not checked.

All rules · ESLint rules