Tokens Overview
Design tokens are the source of truth for every visual decision in the system — color, typography, spacing, shadow, motion. They live as JSON, build into CSS custom properties and TypeScript constants, and validate themselves on every build.
Across global and semantic tiers, both themes.
Raw values: palette, font weights, spacing scale.
Purpose-named tokens that components consume.
Same semantic names, different values per theme.
Two-tier architecture
Tokens come in two tiers. Global primitives define raw values with no meaning — the full palette, every spacing step, every font weight. Semantic aliases point at globals and carry intent — what to use for primary text, default surface, error background. Components only ever consume semantic aliases.
Global primitives
Raw, neutral values. Define what colors and sizes exist, not where they should be used. Never referenced directly by components.
Semantic aliases
Purpose-named. Define where a value belongs. The same alias resolves to different globals across themes — that’s how light and dark work.
color: var(--color-text-primary);
color: var(--color-teal-800); — this is a global; it won’t flip in dark mode.
Naming convention
Tokens are written as dot-paths in JSON and exposed as kebab-case CSS custom properties. The transform is mechanical: dots become hyphens, the whole string is lowercased.
| JSON path | CSS custom property | Resolved value | |
|---|---|---|---|
color.text.primary | → | --color-text-primary | #115662 |
spacing.inset.md | → | --spacing-inset-md | 16px |
type.body.md | → | --type-body-md-size, --type-body-md-lineheight, … | composite |
border.radius.component | → | --border-radius-component | 8px |
--type-h1-size, --type-h1-lineheight.Build pipeline
A single Node script reads the JSON, resolves references, validates contrast, and emits CSS plus TypeScript. It runs as part of npm run build; you can run it directly with npm run build:tokens.
JSON files
tokens/global/*.json + tokens/semantic/*.json
build-tokens.mjs
Flatten paths, resolve {references}, validate contrast, fail on error.
CSS + TypeScript
tokens-base.css, tokens-light.css, tokens-dark.css, src/lib/tokens.ts
{reference} stops the build with a specific error. WCAG 2.2 AA contrast is checked for ten required pairings — if a token change drops a pairing below 4.5:1, the build exits 1 with the failing combination called out.Theme system
Themes are switched via a single data-theme attribute on <html>. The base CSS defines theme-neutral tokens (typography, spacing, motion, layout). Theme files override only what changes — semantic colors and shadows.
/* tokens-base.css */
:root {
--spacing-4: 16px;
--type-body-md-size: 14px;
/* ...everything theme-neutral */
}
/* tokens-light.css */
[data-theme="light"] {
--color-text-primary: #115662;
--color-surface-default: #FFFFFF;
/* ...semantic colors + shadows */
}
/* tokens-dark.css */
[data-theme="dark"] {
--color-text-primary: #F9FAFB;
--color-surface-default: #0F172A;
/* ...same names, different values */
}data-theme instead of a class?<head> that prevents flash-of-wrong-theme. The attribute is also easier to query in JavaScript than a class.Categories
Tokens are organized by what they describe. The first segment of the path identifies the category — color.*, spacing.*, type.*, and so on.
- color.*124 tokens
Brand colors, semantic text and surface colors, action and feedback states.
- type.*13 tokens
Display, heading, body, label, caption, code — composite tokens with size, weight, and line-height.
- font.*26 tokens
Font families, weights, sizes, and line heights — referenced by composite type tokens.
- spacing.*24 tokens
4px-based scale plus semantic aliases for inset, inline, stack, content, and section gaps.
- border.*14 tokens
Radius and width values for components, containers, and focus rings.
- motion.*9 tokens
Duration and easing tokens for transitions and animations.
- breakpoint.*4 tokens
Four breakpoint widths for documentation and JavaScript matchMedia.
- layout.*5 tokens
Container widths, grid gutters, and surface dimensions.
- z-index.*8 tokens
Layering scale for stacking context: dropdown, sticky, modal, toast, etc.