design-no-raw-color-literal
| Field | Value |
|---|---|
| Tool | ESLint |
| Enable via | design() factory |
| Rule ID | house-rules/design-no-raw-color-literal |
| Type | suggestion |
| Autofix | no |
| Source | packages/rules/src/design-no-raw-color-literal.mjs |
| Docs | packages/rules/docs/design-no-raw-color-literal.md |
What it catches
Section titled “What it catches”Raw hex, rgb(), hsl(), etc. in JS/TS strings.
In one line
Section titled “In one line”Disallow raw hex colours and colour functions inside JavaScript and TypeScript strings.
Messages
Section titled “Messages”rawColor: Raw colour “{{color}}” in a string. Use a design token, such as var(–name) or a theme constant.
Default options
Section titled “Default options”[ { "skipVarFallback": true, "allowIn": [] }]Rule docs
Section titled “Rule docs”From packages/rules/docs/design-no-raw-color-literal.md.
Rule ID: house-rules/design-no-raw-color-literal
The rule runs on JavaScript and TypeScript, JSX and TSX included. It reports a hex colour or a colour function written inside a string literal or template text. Use the @house-rules/rules/design factory to enable it.
<div style={{ color: "var(--ink)" }} /> // passes<div style={{ color: "#2b3133" }} /> // reported<rect stroke="var(--pop, #06707e)" /> // passes: a var() fallbackconst html = `<style>body { color: #1c1917; }</style>`; // reported<span>open bundle ↗</span> // passes: an HTML entityThe message is Raw colour "#2b3133" in a string. Use a design token, such as var(--name) or a theme constant.
What the rule checks
Section titled “What the rule checks”It reads every string Literal and every template text part (TemplateElement). It reports:
- a hex colour with 3, 4, 6 or 8 digits
- a call to
rgb(),rgba(),hsl(),hsla(),hwb(),lab(),lch(),oklab(),oklch()orcolor()that contains a number
Named colours are not checked. In code, "red" is too often a word rather than a colour.
A match must start the string or follow whitespace, a quote, or one of : ( , = ; { [ > |. This keeps out:
- HTML entities, such as
↗ - URL fragments, such as
/page#cafeorhttps://example.com/#fade - template text right after
${…}, such as`${base}#fff`
The rule also skips:
- the value of an
href,to,src,actionorxlinkHrefattribute or object key, so<a href="#fade">passes - a hex inside an absolute URL, such as
https://x.test/?q=#fff - a hex right after a query key, such as
/search?q=#fffor&q=#fff - a hex as the value of a CSS attribute selector, such as
[data-id="#add"]or[data-x=#bead] - a colour function that uses
var(), such asrgb(var(--ink-rgb) / 0.5) - a colour in a
var()fallback, unlessskipVarFallbackisfalse
Options
Section titled “Options”type Options = [ { skipVarFallback?: boolean; // default: true allowIn?: string[]; // default: [] },];skipVarFallback: ignore colours in the fallback ofvar(--x, …). The token is used; the fallback only matters when the token is missing.allowIn: file globs, relative to ESLint’s working directory, where the rule does nothing. It supports**,*,?,[...]and{a,b}. As in minimatch, a wildcard does not match a name that starts with., so**/*.tsskips.env.tsand.github/x.ts; write the dot, as in.github/**, to match one. Use it for a theme module that owns the raw values, or a standalone page that cannot load the token stylesheet.
Limitations
Section titled “Limitations”- A string such as
"issue #123"is reported, because#123is a valid colour. - A hex after
=in other contexts is still reported, such as"a=#fff"or<rect fill=#fff>. Only a query key (?q=or&q=) and an attribute selector ([name=) are skipped. - JSX text children are not checked.
- The rule has no autofix.