The Problem With Copy-Pasting Hex Codes
Every developer has been there. A designer hands you a Figma file with #1A1B2E for the background, #E2E3F0 for text, and #7C5CFC for the accent. You hard-code them into your components. Two weeks later, the designer tweaks the accent to #6D4FE8 and you’re grepping through 47 files.
Design tokens solve this by creating a shared vocabulary between design and code. Instead of hex codes scattered everywhere, you have named values that flow from one source of truth into every surface that needs them.
What Are Design Tokens, Really?
A design token is just a named value. That’s it. No special tooling required. The power comes from the naming convention and the propagation strategy.
Here’s a minimal token set:
:root {
/* Primitives — raw values, never referenced directly in components */
--color-slate-950: #0a0b14;
--color-slate-100: #e2e3f0;
--color-violet-500: #7c5cfc;
/* Semantics — what the color means, referenced in components */
--color-bg: var(--color-slate-950);
--color-text: var(--color-slate-100);
--color-accent: var(--color-violet-500);
--color-border: rgba(255, 255, 255, 0.08);
--color-glass: rgba(255, 255, 255, 0.03);
}The two-layer approach is key. Primitives are the raw palette. Semantics map intent to palette. When the designer changes the accent color, you update one primitive. When you want a dark/light theme, you swap the semantic mappings.
Wiring Tokens Into Tailwind
Tailwind CSS makes this straightforward with theme.extend in your config:
export default {
theme: {
extend: {
colors: {
bg: 'var(--color-bg)',
text: 'var(--color-text)',
accent: 'var(--color-accent)',
border: 'var(--color-border)',
glass: 'var(--color-glass)',
}
}
}
};Now your components use semantic class names:
<div class="bg-glass border border-border rounded-xl">
<h2 class="text-text">Section Title</h2>
<a class="text-accent hover:text-text">Learn more</a>
</div>No hex codes in components. No magic numbers. The class names describe intent, not implementation.
Typography Tokens
Colors get all the attention, but typography tokens prevent just as many inconsistencies:
:root {
--font-sans: 'Inter', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-h1: clamp(2.5rem, 5vw, 4rem);
--font-size-h2: clamp(1.75rem, 3vw, 2.5rem);
--font-size-h3: clamp(1.25rem, 2vw, 1.75rem);
}The clamp() functions for headings give you fluid typography that scales smoothly between mobile and desktop — no media queries needed.
Spacing and Radius
Consistency in spacing is what separates a polished UI from a “it looks off but I can’t explain why” UI:
:root {
--space-xs: 0.25rem;
--space-sm: 0.5rem;
--space-md: 1rem;
--space-lg: 1.5rem;
--space-xl: 2rem;
--space-2xl: 3rem;
--radius-sm: 0.375rem;
--radius-md: 0.75rem;
--radius-lg: 1rem;
--radius-xl: 1.5rem;
}With Tailwind, these map directly to utility classes. Your rounded-xl always means the same thing everywhere.
The Workflow That Works
Here’s how we keep tokens in sync between Figma and code:
- Designer defines tokens in Figma using variables (Figma’s native feature since 2023)
- Export as JSON using the Figma Variables API or a plugin like Tokens Studio
- Transform JSON → CSS custom properties with a simple build script
- Tailwind config references the CSS variables — no manual sync needed
When the designer updates a token in Figma, the change flows through the pipeline and lands in the codebase. No Slack messages asking “what’s the new accent color?”
Start Small
You don’t need 200 tokens on day one. Start with:
- 5-7 colors (bg, text, accent, border, muted, glass, error)
- 2 font families (sans, mono)
- 3-5 font sizes
- A spacing scale
- 2-3 border radii
That covers 90% of what you’ll need. Add tokens as pain points emerge, not preemptively.
Need help building a design system that scales? Let’s talk about bringing consistency to your product.
