TOKENS THAT SURVIVE
Build a design token system that outlives the next visual refresh. Three-layer structure, semantic naming, real-world patterns.
Why most token systems do not survive redesigns
Most design token systems get retired within two years because they encoded the visual values of the day rather than the semantic intent behind them. A token named blue-500 is locked to a blue value forever; a token named accent-primary outlives any colour change because the next designer maps it to whatever blue-equivalent the new system uses.
The single rule that separates token systems that survive from ones that die: name tokens by purpose, not by appearance. accent-primary, surface-base, text-secondary, danger-bg. Never blue-500, gray-900, red-light. The semantic name is the contract; the value is the implementation detail.
The three-layer architecture
Layer 1: primitives. Raw colour, spacing, typography values. blue-50, blue-100, blue-200..., blue-900. space-1, space-2..., space-12. These exist as the underlying scale and rarely change.
Layer 2: semantic. Purpose-named tokens that map to primitives. accent-primary maps to blue-500, accent-hover maps to blue-600, surface-base maps to gray-50, text-primary maps to gray-900. Components reference these, never the primitives directly.
Layer 3: component-scoped. Per-component tokens that map to semantic ones. button-primary-bg maps to accent-primary, card-border maps to border-subtle, nav-active-bg maps to accent-emphasis. Components consume these.
When the brand refresh happens, you change the primitive scale and possibly the semantic-to-primitive mapping. Component-scoped tokens flow through unchanged. The redesign ships in days rather than months.
What to encode and what to leave hard-coded
Encode: colour, spacing, typography (font families, sizes, weights, line heights), border-radius, shadow, motion duration and easing, breakpoint widths.
Do not encode: layout-specific values (max-width of 1280 on the article template), one-off positioning offsets, animation choreography that is unique to a single component. These belong inline; encoding them creates a system that fights itself.
The litmus test: would another component plausibly use this same value? If yes, encode it. If no, hard-code it.
Implementation across the stack
CSS custom properties at the token boundary. Define the primitives and semantics in :root, override in [data-theme="dark"]. Components reference the semantic tokens, never the primitives.
JS-accessible tokens via a generated TypeScript file from the same source. Tools like Style Dictionary, Theo, or a small custom generator produce both CSS variables and TS exports from a single JSON or YAML source. The single source means JS animations and styled components stay in sync with stylesheets.
Document the system in a single page (a Storybook page or a /design page on the site itself) so future contributors find it. Token systems that are not discoverable get bypassed within months by people who do not know they exist.
WHEN YOU ARE READY TO TALK
If you are mid-build on something this guide touches and want a second pair of eyes, the fastest path is a 30-minute call.
BOOK YOUR 30-MIN CALL