Introduction
Design tokens are the atomic values of your design system — colors, spacing, typography, shadows — stored as platform-agnostic data. Instead of hardcoding #3B82F6 in fifty places, you define it once as color.primary.500 and reference it everywhere.
Tokens bridge designers and developers. They give designers a constrained palette and developers a predictable styling API. Tools like Style Dictionary and Figma Variables make tokens the single source of truth across platforms.
This guide covers token architecture, naming conventions, tooling, and transforming tokens into CSS custom properties and Tailwind configs.
Key Concepts
Token Hierarchy
// tokens/primitive.json — raw values
{
"color": {
"blue": { "500": { "value": "#3B82F6" }, "900": { "value": "#1E3A8A" } },
"gray": { "50": { "value": "#F9FAFB" }, "900": { "value": "#111827" } }
},
"spacing": { "1": { "value": "4px" }, "4": { "value": "16px" }, "8": { "value": "32px" } }
}
// tokens/semantic.json — purpose-driven aliases
{
"color": {
"bg": { "primary": { "value": "{color.white}" }, "secondary": { "value": "{color.gray.50}" } },
"text": { "primary": { "value": "{color.gray.900}" }, "brand": { "value": "{color.blue.500}" } }
}
}
Style Dictionary Transform
// style-dictionary.config.js
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'dist/css/',
files: [{ destination: 'variables.css', format: 'css/variables' }],
},
tailwind: {
transformGroup: 'js',
buildPath: 'dist/',
files: [{ destination: 'tailwind-tokens.js', format: 'javascript/es6' }],
},
},
};
Practical Examples
1. CSS Custom Properties Output
:root {
--color-blue-500: #3B82F6;
--color-gray-900: #111827;
--color-bg-primary: #ffffff;
--color-text-primary: var(--color-gray-900);
--color-text-brand: var(--color-blue-500);
--spacing-4: 16px;
}
[data-theme="dark"] {
--color-bg-primary: var(--color-gray-900);
--color-text-primary: #ffffff;
}
2. Tailwind Integration
// tailwind.config.ts
import tokens from './dist/tailwind-tokens';
const config = {
theme: {
extend: {
colors: {
brand: { DEFAULT: tokens.ColorBlue500, light: tokens.ColorBlue100 },
},
},
},
};
3. TypeScript Token Types
export const tokens = {
color: {
bg: { primary: 'var(--color-bg-primary)', secondary: 'var(--color-bg-secondary)' },
text: { primary: 'var(--color-text-primary)', brand: 'var(--color-text-brand)' },
},
spacing: { sm: 'var(--spacing-2)', md: 'var(--spacing-4)', lg: 'var(--spacing-8)' },
} as const;
Best Practices
- ✅ Use three tiers: primitive → semantic → component tokens
- ✅ Name by purpose, not appearance (text-primary not text-dark)
- ✅ Store tokens in JSON for tool-agnostic transformation
- ✅ Use Style Dictionary for automated multi-platform output
- ✅ Version tokens alongside your component library
- ❌ Don't reference primitives directly in components — use semantic tokens
- ❌ Don't create tokens for one-off values — tokens should be reusable
Common Pitfalls
- Too many tokens — a 500-shade palette creates decision fatigue
- Naming by current value (blue-button) instead of purpose (action-primary)
- Not planning for dark mode from the start — retrofitting semantic tokens is painful
- Figma and code tokens diverging — automate the sync
Related Guides
- Theming with CSS Variables — Implementing token-based themes
- Building Component Libraries — Using tokens in component styles
- Figma to Code Workflow — Extracting tokens from design files
- Design System Versioning — Managing token changes across versions