Right, so design tokens. If you've been building design systems for a while, you've probably heard this term thrown around heaps. But what are they actually, and why should you care?
Let me break it down for you.
Design tokens are basically named variables that store your design decisions. Think of them as the building blocks of your design system. Instead of hardcoding colours and spacing everywhere, you create reusable values that any platform can understand.
Here's a simple example:
{
"color": {
"primary": {
"500": "#3B82F6",
"600": "#2563EB",
"700": "#1D4ED8"
}
},
"spacing": {
"xs": "4px",
"sm": "8px",
"md": "16px",
"lg": "24px"
}
}
Your brand colours and semantic meanings all in one place:
{
"color": {
"brand": {
"primary": "#3B82F6",
"secondary": "#10B981"
},
"semantic": {
"success": "#059669",
"warning": "#D97706",
"error": "#DC2626",
"info": "#0284C7"
},
"neutral": {
"50": "#F9FAFB",
"100": "#F3F4F6",
"900": "#111827"
}
}
}
Keep your text styling consistent across everything:
{
"typography": {
"fontFamily": {
"sans": ["Inter", "system-ui", "sans-serif"],
"mono": ["Fira Code", "monospace"]
},
"fontSize": {
"xs": "12px",
"sm": "14px",
"base": "16px",
"lg": "18px",
"xl": "20px",
"2xl": "24px"
},
"fontWeight": {
"normal": "400",
"medium": "500",
"semibold": "600",
"bold": "700"
}
}
}
This is where the magic happens. Consistent spacing throughout your entire app:
{
"spacing": {
"0": "0px",
"1": "4px",
"2": "8px",
"3": "12px",
"4": "16px",
"5": "20px",
"6": "24px",
"8": "32px",
"10": "40px",
"12": "48px",
"16": "64px"
}
}
Because nobody wants wonky rounded corners:
{
"borderRadius": {
"none": "0px",
"sm": "2px",
"md": "4px",
"lg": "8px",
"xl": "12px",
"full": "9999px"
}
}
These are your base values that rarely change:
{
"color": {
"blue": {
"500": "#3B82F6"
}
}
}
These reference your global tokens but give them meaning:
{
"color": {
"action": {
"primary": "{color.blue.500}"
}
}
}
Specific values for individual components:
{
"button": {
"primary": {
"background": "{color.action.primary}",
"text": "{color.white}"
}
}
}
Alright, you've got your tokens defined. Now what? Let's look at how to actually implement them in your projects.
Style Dictionary is probably the most popular tool for this stuff. It's an Amazon open-source project that takes your design tokens (written in JSON) and transforms them into whatever format you need. CSS variables, SCSS, JavaScript objects, iOS Swift files, Android XML - you name it.
The beauty of Style Dictionary is that you write your tokens once and it spits out platform-specific files. So your mobile team gets their native formats while your web team gets CSS variables.
Here's how you set it up:
// config.json
{
"source": ["tokens/**/*.json"],
"platforms": {
"css": {
"transformGroup": "css",
"buildPath": "dist/css/",
"files": [{
"destination": "variables.css",
"format": "css/variables"
}]
},
"js": {
"transformGroup": "js",
"buildPath": "dist/js/",
"files": [{
"destination": "tokens.js",
"format": "javascript/es6"
}]
},
"ios": {
"transformGroup": "ios",
"buildPath": "dist/ios/",
"files": [{
"destination": "tokens.swift",
"format": "ios-swift/class.swift"
}]
}
}
}
Run style-dictionary build
and boom - you've got tokens for every platform.
It's pretty neat once you get the hang of it.
Turn your tokens into CSS custom properties:
:root {
--color-primary-500: #3b82f6;
--color-primary-600: #2563eb;
--spacing-4: 16px;
--spacing-8: 32px;
--border-radius-md: 4px;
}
.button {
background-color: var(--color-primary-500);
padding: var(--spacing-4);
border-radius: var(--border-radius-md);
}
Export them as proper objects you can use in your code:
export const tokens = {
color: {
primary: {
500: '#3B82F6',
600: '#2563EB',
},
},
spacing: {
4: '16px',
8: '32px',
},
} as const;
// Usage in React
const Button = () => (
<button
style={{
backgroundColor: tokens.color.primary[500],
padding: tokens.spacing[4],
}}
>
Click me
</button>
);
Different values for different screen sizes:
{
"spacing": {
"section": {
"mobile": "24px",
"tablet": "32px",
"desktop": "48px"
}
}
}
Light mode, dark mode, whatever mode:
{
"theme": {
"light": {
"background": "#FFFFFF",
"text": "#111827"
},
"dark": {
"background": "#111827",
"text": "#F9FAFB"
}
}
}
Sometimes you need tokens that combine multiple properties:
{
"shadow": {
"sm": {
"x": "0px",
"y": "1px",
"blur": "2px",
"spread": "0px",
"color": "{color.neutral.900}",
"opacity": "0.05"
}
}
}
// tailwind.config.js
const tokens = require('./tokens.json');
module.exports = {
theme: {
colors: tokens.color,
spacing: tokens.spacing,
borderRadius: tokens.borderRadius,
fontFamily: tokens.typography.fontFamily,
},
};
import styled, { ThemeProvider } from 'styled-components';
import { tokens } from './tokens';
const Button = styled.button`
background-color: ${(props) => props.theme.color.primary[500]};
padding: ${(props) => props.theme.spacing[4]};
border-radius: ${(props) => props.theme.borderRadius.md};
`;
// Usage
<ThemeProvider theme={tokens}>
<Button>Click me</Button>
</ThemeProvider>;
Use names that make sense:
{
"color": {
"text": {
"primary": "#111827",
"secondary": "#6B7280",
"disabled": "#9CA3AF"
}
}
}
Don't name things after how they look:
// ❌ Avoid
{
"color": {
"blue500": "#3B82F6"
}
}
// ✅ Prefer
{
"color": {
"action": {
"primary": "#3B82F6"
}
}
}
Structure your tokens in a way that makes sense:
{
"component": {
"button": {
"primary": {
"background": {
"default": "{color.action.primary}",
"hover": "{color.action.primaryHover}",
"disabled": "{color.neutral.300}"
}
}
}
}
}
Use proper versioning for your token updates:
{
"version": "2.1.0",
"tokens": {
// token definitions
}
}
When you need to deprecate old tokens:
{
"color": {
"primary": "#3B82F6", // deprecated: use color.action.primary
"action": {
"primary": "#3B82F6"
}
}
}
Different platforms need different formats:
// iOS
const iosTokens = {
colorPrimary500: UIColor(red: 59/255, green: 130/255, blue: 246/255, alpha: 1)
};
// Android
const androidTokens = {
color_primary_500: "#3B82F6"
};
Track a few key things:
The token world is moving pretty fast:
Look, design tokens aren't just fancy variables. They're the backbone of any decent design system. Get them right, and you'll save yourself heaps of time and headaches down the track.
Here's what you get when you do this properly:
Start small with just colours and spacing. Once you've got the hang of it, expand to typography, shadows, and component-specific stuff. Trust me, the time you invest upfront pays off big time later.
The design world is moving towards tokens whether you like it or not, so you might as well get on board now. Your future self will thank you for it.