Core concept 02
Design Tokens
A three-tier hierarchy that separates what a value is from what it means from where it's used. Change once, update everywhere.
The three tiers
The core problem tokens solve is the difference between a colour and its purpose. #d97706 is an amber colour. --accent-default is "the primary accent colour in this system." Those are different things, and conflating them causes maintenance pain.
Token naming
Tokens should describe purpose, not appearance. When a token's name describes what it looks like rather than what it does, renaming or retheming it becomes impossible without touching every reference.
Naming convention
Semantic tokens follow a [category]-[concept]-[variant]-[state] pattern. Categories group related tokens and make the namespace scannable.
| Category | Examples | Covers |
|---|---|---|
--surface-* | --surface-page, --surface-raised | Background colours by elevation |
--text-* | --text-primary, --text-tertiary | Text colours by visual weight |
--border-* | --border-subtle, --border-default | Border colours by prominence |
--accent-* | --accent-default, --accent-subtle | Brand / accent colour roles |
--interactive-* | --interactive-default, --interactive-hover | Interactive element colours |
--shadow-* | --shadow-sm, --shadow-lg | Elevation shadows |
Figma Variables connection
If your Figma Variable names mirror your CSS custom property names, there is zero translation cost between design and code. A Figma variable named color/surface/raised maps directly to --surface-raised in CSS.
High-leverage naming parity
When Figma Variable collections match CSS @layer tokens — light collection maps to :root, dark collection maps to [data-theme="dark"] — exporting tokens to CSS becomes a mechanical transform with no human interpretation required.
/* Figma Variables export (JSON) */ { "color/surface/raised": { "value": "#ffffff" }, "color/accent/default": { "value": "#d97706" } } /* Style Dictionary transforms to CSS */ @layer tokens { :root { --surface-raised: #ffffff; --accent-default: #d97706; } }
Live token values
These swatches show the current resolved value of each semantic token. Toggle the theme to watch them update — the swatch backgrounds are set as background-color: var(--token-name) and the browser resolves them live.
Live token swatches — toggle dark mode to see them change
| Token | Description |
|---|
Token reference
Space
Based on a 4px grid. Use these instead of arbitrary values.
| Token | Value | px |
|---|---|---|
--space-1 | 0.25rem | 4px |
--space-2 | 0.5rem | 8px |
--space-3 | 0.75rem | 12px |
--space-4 | 1rem | 16px |
--space-5 | 1.25rem | 20px |
--space-6 | 1.5rem | 24px |
--space-8 | 2rem | 32px |
--space-10 | 2.5rem | 40px |
--space-12 | 3rem | 48px |
--space-16 | 4rem | 64px |
--space-20 | 5rem | 80px |
--space-24 | 6rem | 96px |
--space-32 | 8rem | 128px |
Typography scale
Major Third ratio (1.25×). Use clamp() for responsive headings.
| Token | Value | ~px |
|---|---|---|
--size-3xs | 0.512rem | ~8px |
--size-2xs | 0.64rem | ~10px |
--size-xs | 0.8rem | ~13px |
--size-sm | 1rem | 16px — body |
--size-md | 1.25rem | 20px |
--size-lg | 1.563rem | 25px |
--size-xl | 1.953rem | 31px |
--size-2xl | 2.441rem | 39px |
--size-3xl | 3.052rem | 49px |
--size-4xl | 3.815rem | 61px |
--size-5xl | 4.768rem | 76px |
Font families
| Token | Value | Use for |
|---|---|---|
--font-serif | Instrument Serif, Georgia | Headings, display text, blockquotes |
--font-sans | Outfit, system-ui | Body text, UI labels, metadata |
--font-mono | JetBrains Mono, Fira Code | Code, technical content, labels |