Skip to content
Design

Design Tokens Complete Guide

Define colors, spacing, typography as tokens — the foundation of any scalable design system.

stellae.design

10 min read

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

json
// 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" } }
}
json
// 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

javascript
// 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

css
: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

typescript
// 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

typescript
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

Designdesign

Was this article helpful?