Design System Tokens
Design token management with W3C Design Token Community Group specification, three-tier token hierarchy (global/alias/component), OKLCH color spaces, Style Dictionary transformation, and dark mode theming. Use when creating design token files, implementing theme systems, managing token versioning, or building design-to-code pipelines.
Primary Agent: frontend-ui-developer
Design System Tokens
Design token management following the W3C Design Token Community Group (DTCG) specification. Tokens provide a single source of truth for design decisions โ colors, spacing, typography, elevation โ shared between design tools (Figma, Penpot) and code (CSS, Tailwind, iOS, Android). Major adopters include Figma (Variables API), Google (Material Design 3), Microsoft (Fluent UI), and Shopify (Polaris).
Quick Reference
| Category | Rule File | Impact | When to Use |
|---|---|---|---|
| W3C Token Format | tokens-w3c-format.md | CRITICAL | Creating or reading .tokens.json files |
| Contrast Enforcement | tokens-contrast-enforcement.md | CRITICAL | Validating WCAG contrast at token definition time |
| Three-Tier Hierarchy | tokens-three-tier.md | HIGH | Organizing tokens into global/alias/component layers |
| OKLCH Color Space | tokens-oklch-color.md | HIGH | Defining colors with perceptual uniformity |
| Spacing & Depth | tokens-spacing-depth.md | HIGH | Defining elevation shadows and spacing scales as tokens |
| Style Dictionary | tokens-style-dictionary.md | HIGH | Transforming tokens to CSS/Tailwind/iOS/Android |
| Theming & Dark Mode | tokens-theming-darkmode.md | HIGH | Implementing theme switching and dark mode |
| Versioning | tokens-versioning.md | HIGH | Evolving tokens without breaking consumers |
Total: 8 rules across 8 categories
Quick Start
W3C DTCG token format (.tokens.json):
{
"color": {
"primary": {
"50": {
"$type": "color",
"$value": "oklch(0.97 0.01 250)",
"$description": "Lightest primary shade"
},
"500": {
"$type": "color",
"$value": "oklch(0.55 0.18 250)",
"$description": "Base primary"
},
"900": {
"$type": "color",
"$value": "oklch(0.25 0.10 250)",
"$description": "Darkest primary shade"
}
}
},
"spacing": {
"sm": {
"$type": "dimension",
"$value": "8px"
},
"md": {
"$type": "dimension",
"$value": "16px"
},
"lg": {
"$type": "dimension",
"$value": "24px"
}
}
}Three-Tier Token Hierarchy
Tokens are organized in three layers โ each referencing the layer below:
| Tier | Purpose | Example |
|---|---|---|
| Global | Raw values | color.blue.500 = oklch(0.55 0.18 250) |
| Alias | Semantic meaning | color.primary = \{color.blue.500\} |
| Component | Scoped usage | button.bg = \{color.primary\} |
This separation enables theme switching (swap alias mappings) without touching component tokens.
{
"color": {
"blue": {
"500": { "$type": "color", "$value": "oklch(0.55 0.18 250)" }
},
"primary": { "$type": "color", "$value": "{color.blue.500}" },
"action": {
"default": { "$type": "color", "$value": "{color.primary}" }
}
}
}OKLCH Color Space
OKLCH (Oklab Lightness, Chroma, Hue) provides perceptual uniformity โ equal numeric changes produce equal visual changes. This solves HSL's problems where hsl(60, 100%, 50%) (yellow) appears far brighter than hsl(240, 100%, 50%) (blue) at the same lightness.
/* OKLCH: L (0-1 lightness), C (0-0.4 chroma/saturation), H (0-360 hue) */
--color-primary: oklch(0.55 0.18 250);
--color-primary-hover: oklch(0.50 0.18 250); /* Just reduce L for darker */Key advantage: adjusting lightness channel alone creates accessible shade scales with consistent contrast ratios.
Detailed Rules
Each rule file contains incorrect/correct code pairs and implementation guidance.
Read("${CLAUDE_SKILL_DIR}/rules/tokens-w3c-format.md")
Read("${CLAUDE_SKILL_DIR}/rules/tokens-contrast-enforcement.md")
Read("${CLAUDE_SKILL_DIR}/rules/tokens-three-tier.md")
Read("${CLAUDE_SKILL_DIR}/rules/tokens-oklch-color.md")
Read("${CLAUDE_SKILL_DIR}/rules/tokens-spacing-depth.md")
Read("${CLAUDE_SKILL_DIR}/rules/tokens-style-dictionary.md")
Read("${CLAUDE_SKILL_DIR}/rules/tokens-theming-darkmode.md")
Read("${CLAUDE_SKILL_DIR}/rules/tokens-versioning.md")
Style Dictionary Integration
Style Dictionary transforms W3C tokens into platform-specific outputs (CSS custom properties, Tailwind theme, iOS Swift, Android XML). Configure a single config.json to generate all platform outputs from one token source.
See rules/tokens-style-dictionary.md for configuration patterns and custom transforms.
Dark Mode & Theming
Token-based theming maps alias tokens to different global values per theme. Dark mode is one theme โ you can support any number (high contrast, brand variants, seasonal).
:root {
--color-surface: oklch(0.99 0.00 0);
--color-on-surface: oklch(0.15 0.00 0);
}
[data-theme="dark"] {
--color-surface: oklch(0.15 0.00 0);
--color-on-surface: oklch(0.95 0.00 0);
}See rules/tokens-theming-darkmode.md for full theme switching patterns.
Versioning & Migration
Tokens evolve. Use semantic versioning for your token packages, deprecation annotations in token files, and codemods for breaking changes.
{
"color": {
"brand": {
"$type": "color",
"$value": "oklch(0.55 0.18 250)",
"$extensions": {
"com.tokens.deprecated": {
"since": "2.0.0",
"replacement": "color.primary.500",
"removal": "3.0.0"
}
}
}
}
}See rules/tokens-versioning.md for migration strategies.
Key Decisions
| Decision | Recommendation |
|---|---|
| Token format | W3C DTCG .tokens.json with $type/$value |
| Color space | OKLCH for perceptual uniformity |
| Hierarchy | Three-tier: global, alias, component |
| Build tool | Style Dictionary 4.x with W3C parser |
| Theming | CSS custom properties with data-theme attribute |
| Token references | Use \{path.to.token\} alias syntax |
Anti-Patterns (FORBIDDEN)
- Hardcoded values in components: Always reference tokens, never raw
#hexor16px - Flat token structure: Use three-tier hierarchy for theme-ability
- HSL for shade scales: OKLCH produces perceptually uniform scales; HSL does not
- Skipping
$type: Every token must declare its type for tooling compatibility - Theme via class toggling raw values: Use semantic alias tokens that remap per theme
- Unversioned token packages: Token changes break consumers; use semver
References
| Resource | Description |
|---|---|
| references/w3c-token-spec.md | W3C DTCG specification overview |
| references/style-dictionary-config.md | Style Dictionary 4.x configuration guide |
| references/token-naming-conventions.md | Naming patterns and conventions |
Agent Integration
The design-system-architect agent orchestrates token workflows end-to-end โ from Figma Variables extraction through Style Dictionary transformation to theme deployment. When working on token architecture decisions, the agent coordinates with frontend-ui-developer for component token consumption and accessibility skills for contrast validation.
Related Skills
ork:ui-componentsโ Component library patterns (shadcn/ui, Radix)ork:accessibilityโ WCAG compliance, contrast ratiosork:responsive-patternsโ Responsive breakpoints, fluid typographyork:figma-design-handoffโ Figma Variables to tokens pipeline
Rules (8)
Enforce contrast ratios at token definition time, not per component โ CRITICAL
Token-Level Contrast Enforcement
Validate contrast ratios when tokens are defined, not when components are reviewed. If --color-text-muted is 4.3:1 on its paired background, every component using it fails WCAG AA โ and no per-component audit will fix the root cause.
Incorrect:
{
"color": {
"text": {
"muted": { "$type": "color", "$value": "oklch(0.60 0.00 0)" }
}
}
}/* No declared background pairing, no contrast metadata โ silent failure */
--color-text-muted: oklch(0.60 0.00 0);Correct โ W3C DTCG token with contrast metadata:
{
"color": {
"text": {
"primary": {
"$type": "color",
"$value": "oklch(0.15 0.00 0)",
"$description": "Primary body text",
"$extensions": {
"a11y": {
"pairedBackground": "{color.bg.primary}",
"contrastRatio": 12.6,
"wcagLevel": "AAA"
}
}
},
"muted": {
"$type": "color",
"$value": "oklch(0.45 0.00 0)",
"$description": "Secondary/muted text โ must still meet AA",
"$extensions": {
"a11y": {
"pairedBackground": "{color.bg.primary}",
"contrastRatio": 4.7,
"wcagLevel": "AA"
}
}
}
}
}
}Correct โ Style Dictionary build-time contrast check:
// style-dictionary.config.js
StyleDictionary.registerAction({
name: 'validate/contrast',
do(dictionary) {
dictionary.allTokens
.filter(t => t.$extensions?.a11y?.contrastRatio !== undefined)
.forEach(t => {
const { contrastRatio, wcagLevel } = t.$extensions.a11y;
const threshold = wcagLevel === 'AAA' ? 7 : 4.5;
if (contrastRatio < threshold) {
throw new Error(
`Token ${t.name}: contrast ${contrastRatio} < ${threshold} (${wcagLevel})`
);
}
});
},
undo() {}
});Key rules:
Minimum ratios at token definition level:
--color-text-*against paired background: >= 4.5:1 (WCAG AA)--color-text-muted/--color-text-subtle: >= 4.5:1 โ "muted" describes tone, not an a11y exemption--color-border-*against adjacent background: >= 3:1 (WCAG 1.4.11 non-text contrast)--color-icon-*conveying information: >= 3:1--color-interactive-*(links, button labels): >= 4.5:1 against background; >= 3:1 against surrounding body text
Dark mode:
- Recalculate every pair independently for dark theme tokens โ do not assume inversion produces valid contrast
- Pure white (
oklch(1.00 0 0)) on dark backgrounds often exceeds 15:1 and causes eye strain; target 9-12:1 - Document the dark-mode pairing in
$extensions.a11yjust as you do for light mode
Process:
- Every text-role token declares its intended background pair in
$extensions.a11y.pairedBackground - Run
style-dictionary buildas a CI gate โ contrast failures block the build - Review the generated contrast table in pull requests alongside visual diffs
Reference: references/w3c-token-spec.md
Define colors in OKLCH for perceptual uniformity โ HIGH
OKLCH Color Space
Use OKLCH (Oklab Lightness, Chroma, Hue) for all color token definitions. OKLCH is perceptually uniform โ equal numeric changes in lightness produce equal visual changes, unlike HSL where yellow at 50% lightness appears far brighter than blue at 50%.
Incorrect:
{
"color": {
"primary": {
"$type": "color",
"100": { "$value": "#dbeafe" },
"500": { "$value": "#3b82f6" },
"900": { "$value": "#1e3a5f" }
}
}
}/* HSL shade scale โ uneven perception */
--blue-100: hsl(214, 95%, 93%);
--blue-500: hsl(217, 91%, 60%);
--blue-900: hsl(224, 64%, 33%);Correct:
{
"color": {
"primary": {
"$type": "color",
"50": { "$value": "oklch(0.97 0.01 250)" },
"100": { "$value": "oklch(0.93 0.04 250)" },
"200": { "$value": "oklch(0.85 0.08 250)" },
"300": { "$value": "oklch(0.75 0.12 250)" },
"400": { "$value": "oklch(0.65 0.16 250)" },
"500": { "$value": "oklch(0.55 0.18 250)" },
"600": { "$value": "oklch(0.48 0.16 250)" },
"700": { "$value": "oklch(0.40 0.14 250)" },
"800": { "$value": "oklch(0.32 0.10 250)" },
"900": { "$value": "oklch(0.25 0.08 250)" }
}
}
}Key rules:
- OKLCH format:
oklch(L C H)โ L: 0-1 lightness, C: 0-0.4 chroma, H: 0-360 hue - Generate shade scales by varying L (lightness) while keeping H (hue) constant
- Reduce C (chroma) slightly at extremes (very light/dark) to stay within sRGB gamut
- For accessible contrast: ensure 4.5:1 ratio between text and background tokens (WCAG AA)
- Light shades (50-200): L > 0.80; mid shades (300-500): L 0.45-0.75; dark shades (600-900): L < 0.50
- Use CSS
color-mix(in oklch, ...)for runtime blending if needed - All modern browsers support OKLCH natively (Chrome 111+, Safari 15.4+, Firefox 113+)
Reference: references/w3c-token-spec.md
Define elevation and spacing as explicit token scales โ HIGH
Spacing and Depth as Tokens
Every spacing value and shadow must come from a named token โ no magic numbers. Spacing tokens create visual rhythm through proximity grouping; elevation tokens communicate layer hierarchy through a consistent light-source model.
Incorrect:
.card { padding: 12px 20px; box-shadow: 0 3px 8px rgba(0,0,0,0.12); }
.modal { box-shadow: 0 12px 20px rgba(0,0,0,0.18); }
.dropdown { margin-top: 6px; }Correct โ token definitions:
{
"spacing": {
"$type": "dimension",
"xs": { "$value": "4px" },
"sm": { "$value": "8px" },
"md": { "$value": "16px" },
"lg": { "$value": "24px" },
"xl": { "$value": "32px" },
"2xl": { "$value": "48px" },
"3xl": { "$value": "64px" }
},
"elevation": {
"$type": "shadow",
"0": { "$value": "none" },
"1": { "$value": "0 1px 2px rgba(0,0,0,0.05)" },
"2": { "$value": "0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.06)" },
"3": { "$value": "0 10px 15px rgba(0,0,0,0.10), 0 4px 6px rgba(0,0,0,0.05)" },
"4": { "$value": "0 20px 25px rgba(0,0,0,0.15), 0 8px 10px rgba(0,0,0,0.07)" }
}
}Correct โ CSS custom properties:
:root {
--space-xs: 4px; --space-sm: 8px; --space-md: 16px;
--space-lg: 24px; --space-xl: 32px; --space-2xl: 48px;
--elevation-0: none;
--elevation-1: 0 1px 2px rgba(0,0,0,0.05);
--elevation-2: 0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.06);
--elevation-3: 0 10px 15px rgba(0,0,0,0.10), 0 4px 6px rgba(0,0,0,0.05);
--elevation-4: 0 20px 25px rgba(0,0,0,0.15), 0 8px 10px rgba(0,0,0,0.07);
}
/* Component tokens reference the scale */
.card { padding: var(--space-md); box-shadow: var(--elevation-1); }
.popover { box-shadow: var(--elevation-2); }
.modal { box-shadow: var(--elevation-3); }
.toast { box-shadow: var(--elevation-4); }Key rules:
Spacing:
- Base unit is 4px; the scale is geometric: 4, 8, 16, 24, 32, 48, 64
- Start with generous whitespace, then reduce โ under-spaced UIs feel cramped and hard to scan
- Use proximity to signal grouping: related elements share a closer spacing step
- Sibling flow spacing via
* + * \{ margin-block-start: var(--space-md) \}(owl selector)
Elevation (5 levels, top-left light source):
- Level 0 โ flat, inline: no shadow, use background color change to separate regions
- Level 1 โ raised surfaces (cards, list items): single, subtle contact shadow
- Level 2 โ overlays floating above content (dropdowns, popovers): contact + ambient shadows
- Level 3 โ modal dialogs: pronounced contact shadow, heavier ambient shadow
- Level 4 โ highest-priority floating elements (toasts, command palette): maximum shadow
- Every shadow uses two parts: a tight dark contact shadow + a large soft ambient shadow
Flat depth (no shadows needed):
- Layer backgrounds: white card on
--color-bg-secondaryreads as elevated without a shadow - Overlap elements deliberately to imply z-order
- Accent borders (left or top, 2px, brand color) add depth cues without full borders
Reference: references/token-naming-conventions.md
Use Style Dictionary 4.x to transform W3C tokens โ HIGH
Style Dictionary Integration
Use Style Dictionary 4.x with the W3C DTCG parser to transform design tokens into platform-specific outputs. A single token source generates CSS custom properties, Tailwind theme config, iOS Swift constants, and Android XML resources.
Incorrect:
// Manually maintaining separate files per platform
// tokens.css
:root { --color-primary: #3b82f6; }
// tokens.swift
struct Colors { static let primary = UIColor(hex: "#3b82f6") }
// tokens.xml
<color name="colorPrimary">#3b82f6</color>Correct:
// config.mjs โ Style Dictionary 4.x
import { register } from '@tokens-studio/sd-transforms';
import StyleDictionary from 'style-dictionary';
register(StyleDictionary);
const sd = new StyleDictionary({
source: ['tokens/**/*.tokens.json'],
parsers: ['tokens-studio'],
platforms: {
css: {
transformGroup: 'tokens-studio',
buildPath: 'build/css/',
files: [{
destination: 'variables.css',
format: 'css/variables',
options: { outputReferences: true }
}]
},
tailwind: {
transformGroup: 'tokens-studio',
buildPath: 'build/',
files: [{
destination: 'tailwind-tokens.js',
format: 'javascript/es6'
}]
}
}
});
await sd.buildAllPlatforms();Key rules:
- Use Style Dictionary 4.x (ESM) โ v3 does not support W3C format natively
- Enable
outputReferences: trueto preserve alias chains in CSS output - Use
@tokens-studio/sd-transformsfor Tokens Studio / Figma Variables compatibility - Run token builds in CI to catch reference errors before merge
- Custom transforms go in
config.mjsโ never patch generated output files - Separate source files by tier:
tokens/global/,tokens/alias/,tokens/component/
Reference: references/style-dictionary-config.md
Implement theme switching via alias token remapping โ HIGH
Theming & Dark Mode
Implement themes by remapping alias tokens to different global values. Dark mode is one theme among many. Use data-theme attribute on the root element and prefers-color-scheme media query for system preference detection.
Incorrect:
/* Hardcoded dark overrides โ fragile, misses semantics */
.dark .card { background: #1f2937; color: #f9fafb; }
.dark .button { background: #60a5fa; }
.dark .sidebar { background: #111827; }
/* Hundreds of component-level overrides... */Correct:
/* Light theme (default) โ alias tokens mapped to light globals */
:root {
--color-surface: oklch(0.99 0.00 0);
--color-surface-raised: oklch(1.00 0.00 0);
--color-on-surface: oklch(0.15 0.00 0);
--color-on-surface-muted: oklch(0.45 0.00 0);
--color-action: oklch(0.55 0.18 250);
--color-action-hover: oklch(0.48 0.18 250);
--color-border: oklch(0.88 0.00 0);
}
/* Dark theme โ same aliases, different globals */
[data-theme="dark"] {
--color-surface: oklch(0.15 0.00 0);
--color-surface-raised: oklch(0.20 0.01 250);
--color-on-surface: oklch(0.95 0.00 0);
--color-on-surface-muted: oklch(0.65 0.00 0);
--color-action: oklch(0.65 0.16 250);
--color-action-hover: oklch(0.70 0.14 250);
--color-border: oklch(0.30 0.00 0);
}
/* System preference fallback */
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) {
--color-surface: oklch(0.15 0.00 0);
--color-on-surface: oklch(0.95 0.00 0);
/* ... same as [data-theme="dark"] */
}
}// Theme toggle with system preference detection
function initTheme() {
const stored = localStorage.getItem('theme');
if (stored) {
document.documentElement.setAttribute('data-theme', stored);
}
// If no stored preference, :root:not([data-theme]) lets CSS handle it
}
function setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
}Key rules:
- Use
data-themeattribute, not CSS classes, for theme selection - Use
:root:not([data-theme])withprefers-color-schemefor system preference when no explicit choice is set - Components reference only alias tokens (
--color-surface) โ never raw values - Dark mode is not just "invert lightness" โ reduce chroma and adjust contrast for readability
- In dark themes, raise surface lightness slightly for elevated elements (cards, modals)
- Test all themes against WCAG AA contrast requirements (4.5:1 text, 3:1 UI elements)
Reference: references/w3c-token-spec.md
Organize tokens in global, alias, and component tiers โ HIGH
Three-Tier Token Hierarchy
Organize tokens into three layers: global (raw values), alias (semantic meaning), and component (scoped usage). Components reference aliases, aliases reference globals. This enables theme switching by remapping aliases without touching components.
Incorrect:
{
"button": {
"background": { "$type": "color", "$value": "#3b82f6" },
"text": { "$type": "color", "$value": "#ffffff" },
"border-radius": { "$type": "dimension", "$value": "8px" }
},
"card": {
"background": { "$type": "color", "$value": "#ffffff" },
"border": { "$type": "color", "$value": "#e5e7eb" }
}
}Correct:
{
"global": {
"color": {
"blue": {
"$type": "color",
"500": { "$value": "oklch(0.55 0.18 250)" },
"600": { "$value": "oklch(0.48 0.18 250)" }
},
"neutral": {
"$type": "color",
"0": { "$value": "oklch(1.00 0 0)" },
"100": { "$value": "oklch(0.96 0.00 0)" },
"800": { "$value": "oklch(0.27 0.00 0)" }
}
}
},
"alias": {
"color": {
"$type": "color",
"action": { "$value": "{global.color.blue.500}" },
"actionHover": { "$value": "{global.color.blue.600}" },
"surface": { "$value": "{global.color.neutral.0}" },
"onSurface": { "$value": "{global.color.neutral.800}" }
}
},
"component": {
"button": {
"bg": { "$type": "color", "$value": "{alias.color.action}" },
"bgHover": { "$type": "color", "$value": "{alias.color.actionHover}" },
"text": { "$type": "color", "$value": "{global.color.neutral.0}" }
}
}
}Key rules:
- Global tokens are raw values โ colors, sizes, font stacks โ never used directly in components
- Alias tokens add semantic meaning โ
action,surface,onSurface,dangerโ and reference globals - Component tokens scope usage โ
button.bg,card.borderโ and reference aliases - Theme switching remaps alias layer only; component tokens stay unchanged
- Keep global palette complete (all shades); keep alias layer minimal (only used semantics)
- A component token referencing a global directly is a code smell โ add an alias
Reference: references/token-naming-conventions.md
Version token packages with semver and deprecation annotations โ HIGH
Token Versioning & Migration
Version your token packages with semantic versioning. Use $extensions for deprecation metadata. Provide codemods or migration scripts for breaking changes.
Incorrect:
{
"color": {
"brand": { "$type": "color", "$value": "oklch(0.55 0.18 250)" }
}
}# Renaming "brand" to "primary" with no warning, no migration path
git commit -m "rename brand to primary"
# Every consumer breaks silentlyCorrect:
{
"color": {
"brand": {
"$type": "color",
"$value": "{color.primary.500}",
"$extensions": {
"com.tokens.deprecated": {
"since": "2.0.0",
"replacement": "color.primary.500",
"removal": "3.0.0",
"message": "Use color.primary.500 instead"
}
}
},
"primary": {
"$type": "color",
"500": { "$value": "oklch(0.55 0.18 250)" }
}
}
}// codemod for consumers (jscodeshift or custom script)
const tokenMigrations = {
'--color-brand': '--color-primary-500',
'var(--color-brand)': 'var(--color-primary-500)',
};
function migrateCSS(source) {
let result = source;
for (const [old, replacement] of Object.entries(tokenMigrations)) {
result = result.replaceAll(old, replacement);
}
return result;
}Key rules:
- PATCH (1.0.x): New tokens, updated
$description, metadata changes - MINOR (1.x.0): New token groups, new aliases, deprecated tokens (still functional)
- MAJOR (x.0.0): Removed tokens, renamed tokens, changed
$valuesemantics - Always deprecate before removing โ minimum one minor version between deprecation and removal
- Include
replacementpath in deprecation metadata so tooling can auto-migrate - Maintain a
CHANGELOG.mdfor your token package with migration instructions - Run a CI check that flags usage of deprecated tokens in consuming repos
- Publish tokens as an npm package (e.g.,
@myorg/design-tokens) for versioned consumption
Reference: references/token-naming-conventions.md
Use W3C DTCG token format with $type and $value โ CRITICAL
W3C DTCG Token Format
All design tokens must follow the W3C Design Token Community Group specification. Every token requires $type and $value properties. Group tokens hierarchically using nested objects.
Incorrect:
{
"colors": {
"primary": "#3b82f6",
"secondary": "rgb(99, 102, 241)"
},
"spacing": {
"small": 8,
"medium": "16px"
}
}Correct:
{
"color": {
"$type": "color",
"primary": {
"$value": "oklch(0.55 0.18 250)",
"$description": "Primary brand color"
},
"secondary": {
"$value": "oklch(0.50 0.17 280)",
"$description": "Secondary accent color"
}
},
"spacing": {
"$type": "dimension",
"sm": {
"$value": "8px",
"$description": "Compact spacing"
},
"md": {
"$value": "16px",
"$description": "Default spacing"
}
}
}Key rules:
- Every token must have
$value;$typecan be set on the token or inherited from a parent group - Valid
$typevalues:color,dimension,fontFamily,fontWeight,duration,cubicBezier,number,strokeStyle,border,transition,shadow,gradient,typography,fontStyle - Use
$descriptionfor documentation; tooling can extract these for style guides - File extension should be
.tokens.jsonfor tooling auto-detection - Use
$extensionsfor vendor-specific metadata (deprecation, figma-mapping, etc.) - Token names use camelCase; group names use camelCase
- References use curly brace syntax:
"\{color.primary\}"to alias another token
W3C token group inheritance:
{
"spacing": {
"$type": "dimension",
"xs": { "$value": "4px" },
"sm": { "$value": "8px" },
"md": { "$value": "16px" },
"lg": { "$value": "24px" },
"xl": { "$value": "32px" }
}
}All children inherit $type: "dimension" from the parent group โ no need to repeat it.
Reference: W3C Design Tokens Specification
References (3)
Style Dictionary Config
Style Dictionary 4.x Configuration Guide
Overview
Style Dictionary is a build system for transforming design tokens into platform-specific outputs. Version 4.x introduces ESM configuration, the W3C DTCG parser, and improved reference resolution.
Basic Configuration
// config.mjs
import StyleDictionary from 'style-dictionary';
const sd = new StyleDictionary({
source: ['tokens/**/*.tokens.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [{
destination: 'variables.css',
format: 'css/variables',
options: { outputReferences: true }
}]
}
}
});
await sd.buildAllPlatforms();Multi-Platform Output
Add platform entries for each target. Supported transform groups: css, js, ios, android.
// Add to platforms object alongside css:
js: { transformGroup: 'js', buildPath: 'build/js/', files: [{ destination: 'tokens.js', format: 'javascript/es6' }] },
ios: { transformGroup: 'ios', buildPath: 'build/ios/', files: [{ destination: 'Colors.swift', format: 'ios-swift/class.swift', filter: { type: 'color' } }] },
android: { transformGroup: 'android', buildPath: 'build/android/', files: [{ destination: 'colors.xml', format: 'android/colors', filter: { type: 'color' } }] },Tokens Studio Integration
When using Tokens Studio (Figma plugin), use @tokens-studio/sd-transforms:
import { register } from '@tokens-studio/sd-transforms';
import StyleDictionary from 'style-dictionary';
// Register Tokens Studio transforms and parsers
register(StyleDictionary);
const sd = new StyleDictionary({
source: ['tokens/**/*.tokens.json'],
parsers: ['tokens-studio'],
platforms: {
css: {
transformGroup: 'tokens-studio',
buildPath: 'build/css/',
files: [{
destination: 'variables.css',
format: 'css/variables',
options: { outputReferences: true }
}]
}
}
});Custom Transforms
StyleDictionary.registerTransform({
name: 'oklch/css',
type: 'value',
filter: (token) => token.$type === 'color',
transform: (token) => {
// Custom color transformation logic
return token.$value;
}
});Theming with Multiple Files
Generate separate CSS files per theme:
const themes = ['light', 'dark', 'high-contrast'];
for (const theme of themes) {
const sd = new StyleDictionary({
source: [
'tokens/global/**/*.tokens.json',
`tokens/alias/${theme}.tokens.json`,
'tokens/component/**/*.tokens.json'
],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [{
destination: `${theme}.css`,
format: 'css/variables',
options: {
outputReferences: true,
selector: theme === 'light' ? ':root' : `[data-theme="${theme}"]`
}
}]
}
}
});
await sd.buildAllPlatforms();
}Key Options
| Option | Description |
|---|---|
outputReferences: true | Preserve alias chains in output (var(--color-primary)) |
selector | CSS selector for the variables block (default: :root) |
filter | Filter tokens by type, path, or custom function |
transformGroup | Preset group of transforms (css, js, ios, android) |
Token Naming Conventions
Token Naming Conventions
Overview
Consistent token naming is essential for discoverability, tooling compatibility, and team collaboration. This guide covers naming patterns aligned with the W3C DTCG specification and industry best practices.
Naming Structure
Tokens follow a hierarchical dot-notation path: category.concept.modifier.state
| Segment | Examples | Purpose |
|---|---|---|
| Category | color, spacing, typography | What type of value |
| Concept | primary, surface, body | Semantic meaning |
| Modifier | 500, lg, bold | Variant within concept |
| State | hover, active, disabled | Interactive state |
Examples by Category
Colors
color.primary.500 โ Base primary color
color.primary.500.hover โ Hovered state
color.surface.default โ Default background
color.on-surface.default โ Text on default background
color.border.default โ Default border color
color.danger.500 โ Error/danger baseSpacing
spacing.xs โ 4px (extra small)
spacing.sm โ 8px (small)
spacing.md โ 16px (medium / base)
spacing.lg โ 24px (large)
spacing.xl โ 32px (extra large)
spacing.2xl โ 48px (2x extra large)Typography
typography.heading.xl โ Page title
typography.heading.lg โ Section heading
typography.body.md โ Body text
typography.body.sm โ Small body text
typography.label.md โ Form labels
typography.code.md โ Code blocksComponent Tokens
button.bg.default โ Button background
button.bg.hover โ Button hover background
button.text.default โ Button text color
button.border.radius โ Button corner radius
input.bg.default โ Input background
input.border.default โ Input border
input.border.focus โ Input focus border
card.bg.default โ Card background
card.shadow.default โ Card shadow
card.border.radius โ Card corner radiusNaming Rules
- Use camelCase for multi-word segments:
fontSize,lineHeight,borderRadius - Use dot notation for hierarchy:
color.primary.500, notcolor-primary-500 - Semantic over visual:
color.dangernotcolor.red;spacing.mdnotspacing.16 - Consistent state naming:
default,hover,active,focus,disabled - Consistent scale naming: Use t-shirt sizes (
xs,sm,md,lg,xl) or numeric scales (100-900) - No abbreviations except well-known ones:
bg,sm,md,lg,xl,2xl - Prefix component tokens with component name:
button.bg,card.shadow
CSS Custom Property Output
When tokens are transformed to CSS, dots become dashes:
color.primary.500 โ --color-primary-500
spacing.md โ --spacing-md
button.bg.hover โ --button-bg-hoverCommon Mistakes
| Mistake | Why It's Wrong | Better |
|---|---|---|
blue-500 | Visual, not semantic | primary-500 |
small-padding | Mixes concept and category | spacing-sm |
btnBg | Unclear abbreviation | button-bg-default |
color1, color2 | Meaningless names | primary, secondary |
dark-background | Theme-specific naming | surface-default |
Mapping Figma Variables
When exporting from Figma, map variable collections to token tiers:
| Figma Collection | Token Tier | Example |
|---|---|---|
| Primitives | Global | color/blue/500 |
| Tokens | Alias | color/action/default |
| Components | Component | button/bg/default |
W3c Token Spec
W3C Design Token Community Group Specification
Overview
The W3C Design Token Community Group (DTCG) defines a standard file format for design tokens, enabling interoperability between design tools, development platforms, and token management systems. The specification is available at design-tokens.github.io/community-group/format/.
File Format
Token files use JSON with the .tokens.json extension. Each token is an object with $-prefixed properties:
| Property | Required | Description |
|---|---|---|
$value | Yes | The token's resolved value |
$type | Yes* | Token type (can be inherited from parent group) |
$description | No | Human-readable description |
$extensions | No | Vendor-specific metadata |
*$type is required but can be declared on a parent group and inherited by all children.
Token Types
The specification defines these token types:
Simple Types
colorโ CSS color value (hex, rgb, oklch, etc.)dimensionโ Number with unit (16px,1.5rem)fontFamilyโ Font name string or arrayfontWeightโ Numeric weight (100-900) or keyworddurationโ Time value (200ms,0.3s)cubicBezierโ Bezier curve array[x1, y1, x2, y2]numberโ Unitless number
Composite Types
strokeStyleโ Border stroke definitionborderโ Composed of color, width, styletransitionโ Composed of duration, delay, timing functionshadowโ Composed of color, offset, blur, spreadgradientโ Array of color stopstypographyโ Composed of font family, size, weight, line height, letter spacing
Token References (Aliases)
Tokens can reference other tokens using curly brace syntax:
{
"color": {
"blue": {
"500": { "$type": "color", "$value": "oklch(0.55 0.18 250)" }
},
"primary": { "$type": "color", "$value": "{color.blue.500}" }
}
}References are resolved by the token processing tool (e.g., Style Dictionary). Circular references are invalid.
Group Inheritance
A $type set on a group applies to all descendant tokens that don't specify their own $type:
{
"spacing": {
"$type": "dimension",
"sm": { "$value": "8px" },
"md": { "$value": "16px" },
"lg": { "$value": "24px" }
}
}Extensions
The $extensions property allows vendor-specific metadata:
{
"color": {
"primary": {
"$type": "color",
"$value": "oklch(0.55 0.18 250)",
"$extensions": {
"com.figma": { "variableId": "VariableID:123:456" },
"com.tokens.deprecated": { "since": "2.0.0", "replacement": "color.brand.primary" }
}
}
}
}Adoption
Major platforms supporting or converging on the W3C format:
- Figma โ Variables API exports W3C-compatible tokens
- Tokens Studio โ Figma plugin with full W3C support
- Style Dictionary 4.x โ Built-in W3C parser
- Google Material Design 3 โ Aligned with DTCG concepts
- Microsoft Fluent UI โ Token architecture follows DTCG principles
- Shopify Polaris โ Uses token hierarchy patterns from DTCG
- Salesforce Lightning โ Early DTCG contributor
File Organization
Recommended file structure for a token package:
tokens/
โโโ global/
โ โโโ color.tokens.json
โ โโโ spacing.tokens.json
โ โโโ typography.tokens.json
โ โโโ elevation.tokens.json
โโโ alias/
โ โโโ light.tokens.json
โ โโโ dark.tokens.json
โโโ component/
โ โโโ button.tokens.json
โ โโโ card.tokens.json
โ โโโ input.tokens.json
โโโ $metadata.jsonDemo Producer
Creates polished demo videos for skills, tutorials, and CLI demonstrations. Use when producing video showcases, marketing content, or terminal recordings.
Devops Deployment
Use when setting up CI/CD pipelines, containerizing applications, deploying to Kubernetes, or writing infrastructure as code. DevOps & Deployment covers GitHub Actions, Docker, Helm, and Terraform patterns.
Last updated on