Skip to main content
Colorstruct
Sign in
Practice5 min read

Semantic roles beat colour names

A palette of named colours does not survive contact with a product. Roles do — and they make the accessibility checks answerable.

Every design system eventually learns the same lesson: --blue-600is a fact about a colour, not an instruction about where to use it. The moment the brand shifts, every usage has to be re-read to work out which ones meant “primary action” and which ones just happened to be blue.

Two layers, not one

Keep the primitive layer — the actual values, named for what they are — and add a semantic layer on top that names what they do:

  • --color-background, --color-surface, --color-border
  • --color-text, --color-text-muted
  • --color-primary, --color-accent
  • --color-success, --color-warning, --color-danger

Components reference only the semantic layer. Rebranding then means changing the mapping in one file, and a dark theme is a second mapping rather than a second codebase.

Roles make accessibility checkable

This is the part that pays for itself. Once a colour has the role “text” and another has “background”, the question “does this palette work?” stops being vague. There is a specific list of pairs that must pass, at specific thresholds, and it can be checked automatically.

That is exactly what Colorstruct’s inspector does with the roles you assign: body text on page, muted text on page, primary control on page, border on surface. Unassigned colours are simply not checked, because there is nothing to check them against.

A practical starting set

Five to seven colours covers most interfaces: a page background, a surface, a text colour, a muted text colour, a primary, an accent, and a border. Status colours can often be derived from the accent hue rather than added as new hues, which keeps the palette coherent.

Put it to work

Everything described here is built into the workspace. No account needed.

Keep reading