Design tokens
Express every UI design decision — color, spacing, typography, radius, motion, elevation, opacity — once as a named design token in a single platform-agnostic source of truth, then generate platform artifacts from it. Application code and components MUST reference semantic tokens, never raw values, so one edit propagates everywhere.
Single source of truth
- Design decisions MUST live in one shared source, not duplicated per platform.
- The source format SHOULD be the W3C Design Tokens Community Group (DTCG) JSON format, which reached its first stable version (2025.10) in October 2025. Pin to a dated revision (e.g.
2025.10) rather than tracking the living draft, which carries a do-not-implement notice. - Each token MUST carry an explicit
$type(e.g.color,dimension,duration,fontFamily) and a$value; design intent SHOULD be captured in$description. - Platform outputs (Swift, Kotlin, TypeScript/CSS custom properties, C#/XAML) SHOULD be generated by a build step (e.g. Style Dictionary) — never hand-maintained copies.
Three tiers
Use three layers so values change in one place and intent stays stable:
| Tier | Holds | Example | May code reference it? |
|---|---|---|---|
| Primitive (global) | Raw, context-free values | color.blue.600 = #2563EB |
No |
| Semantic (alias) | Intent, references a primitive | color.action.primary → color.blue.600 |
Yes |
| Component | Per-component intent | button.bg.default → color.action.primary |
Yes |
- Components and application code MUST reference semantic or component tokens only; they MUST NOT reference primitives directly.
- Semantic and component tokens MUST be aliases (DTCG
{token.path}references), not duplicated literals, so a primitive change cascades automatically. - Tier count SHOULD stay at three; add a component tier only when a real second consumer exists (YAGNI) — a flat alias layer is enough for a single app.
Theming and modes
- Variants (light/dark, density, brand) SHOULD be modeled by swapping the semantic layer's primitive references, leaving component tokens untouched.
- Mode-specific values SHOULD be expressed as sets/themes resolved at build or runtime; the component contract stays identical across modes.
- Naming MUST be consistent and platform-neutral (
color.action.primary), so the same identifier resolves on every platform.
Accessibility and validation
- Color-pair tokens (foreground on background) SHOULD be checked for WCAG 2.2 contrast (4.5:1 body text, 3:1 large text/UI) in the token pipeline, failing the build on violation.
- The token file SHOULD be schema-validated in CI so malformed or dangling aliases fail fast rather than shipping.
Anti-patterns
- Do NOT hardcode hex/spacing/font literals in components — that defeats single-source propagation.
- Do NOT reference primitive tokens from components; an intent change then requires editing many call sites.
- Do NOT fork per-platform token copies; divergence is inevitable.
Privacy/compliance note: this is engineering guidance, not legal advice.