Design tokens explained: from raw values to semantic roles
A design token is a named design decision: a colour, a size, a spacing step, a radius, a duration. Instead of writing #1d4ed8 in forty places, you write --action and define it once. Tokens become powerful when they're named by role rather than by value, because then a theme or a rebrand is a change to a few definitions.
Why name a value at all
Every site has design values: the blue of the buttons, the grey of captions, the 24px between cards. Without tokens, those values are typed directly wherever they're used. Changing the blue means finding every instance, including the ones written slightly differently (#1D4ED8, rgb(29, 78, 216)), and inevitably missing one. A token gives the value a single home and a name, and everything else refers to the name.
The term came out of large product teams who needed the same decisions to reach websites, iOS apps and Android apps, each written in a different language. Tokens stored in one neutral format could be translated into CSS, Swift or XML automatically. On a small website the same idea, design tokens explained in one line, is simply CSS custom properties with good names.
The layers
| Layer | Named for | Example | Changes when |
|---|---|---|---|
| Primitive (or core) | The value itself | --blue-700: #1d4ed8 | The palette is redesigned |
| Semantic | The role it plays | --action: var(--blue-700) | A theme or brand changes |
| Component | One component's part | --button-bg: var(--action) | One component is restyled |
Primitives are the full set of available values: every shade, every size. On their own they don't tell anyone which to use. Semantic tokens are the important layer. They name a job (surface, text, muted text, border, action, on-action, danger) and point to a primitive. Components use semantic tokens, never primitives directly, so a button doesn't know it's blue, only that it's the action colour.
Component tokens are optional. Large systems use them to restyle one component without touching the rest; small sites can usually skip them and refer to semantic tokens from component styles directly.
How tokens make themes work
With semantic tokens, a dark theme isn't a second stylesheet. It's a second set of definitions for the same names. In light mode --ground might be a warm off-white and --text a near-black; in dark mode --ground becomes charcoal and --text an off-white. Every component that uses those names changes with them, and nothing in the components themselves is touched.
The same applies to rebrands and seasonal changes. If the action colour changes from blue to green, one definition changes and every button, link and focus ring follows. It's also what keeps hand edits consistent: someone adding a new section uses --muted for its captions and gets the right grey in both themes without thinking about it.
Writing tokens in CSS
- Define primitives and semantics on
:root. For example--ground: #fbfaf6; --text: #17160f; --action: #1f3a5f;. - Override semantics for themes inside a
[data-theme="dark"]selector or aprefers-color-schememedia query. - Use only semantic names in components. A rule like
.button { background: var(--action); color: var(--on-action); }survives every theme. - Include non-colour decisions: type sizes, spacing steps, radii, durations and easing curves are tokens too.
- Keep the list short. A small site needs perhaps eight colour roles, six type sizes, eight spacing steps, two or three radii and two curves.
Naming without regret
- Name by role, not appearance.
--actionoutlives--bluethe day the brand turns green. - Avoid names tied to one place.
--hero-bginvites a different token for every section;--surface-inversecan be reused. - Pair every background with its text. If you have
--action, have--on-action; if you have--surface, know which text token sits on it. - Use a consistent scale for sizes. Numbered steps (
--space-1to--space-8) or t-shirt sizes, not a mix.
The W3C Design Tokens Community Group has been working on a shared file format so tokens can move between design tools and code. For a single website, CSS custom properties are all you need; the format matters when tokens must travel between tools.
Tokens in Anticode
Anticode's design systems are expressed as tokens. Each system defines a small set of semantic colour roles, the ground, surface, text, muted text, line, action colour, the text that sits on the action colour, and a secondary colour for systems that use one, with separate values for light and dark themes. Alongside them sit tokens for corner radius by role, spacing, and the easing curves and durations used for motion.
Switching theme or action colour swaps the token values, and every part of the page follows. You can also tune individual colour tokens to your own values, which is how you bring a brand colour into a system. The checks still run on the result, but contrast between your own values is yours to verify: colour contrast for websites explains what to check.
Questions people ask
Are CSS variables the same as design tokens?
CSS custom properties are one way to implement tokens on the web. Tokens are the named decisions; custom properties are how a website stores and uses them.
What's the difference between primitive and semantic tokens?
Primitives name values (--blue-700). Semantic tokens name jobs (--action) and point to a primitive. Components should use semantic tokens.
How many design tokens does a small website need?
Usually a few dozen: about eight colour roles per theme, six type sizes, eight spacing steps, a few radii and two or three motion values.