What Are Design Tokens? A Practical Guide for Frontend Developers
What Are Design Tokens?
Design tokens are named, reusable values that represent the visual properties of a design system. They're the single source of truth for colors, spacing, typography, border radius, shadows, and other style decisions that define how your product looks and feels.
Instead of scattering raw values like #3b82f6 or 16px throughout your codebase, you assign them names like color-primary or spacing-4. Every component references the token, not the raw value. When you change the token, every component updates automatically.
The term was coined by Salesforce's design team in 2014 when they built the Lightning Design System. The idea is simple: separate design decisions from implementation. A color token doesn't care if it's consumed by a React component, an iOS native view, or a Figma plugin. The value is the same everywhere.
Why Design Tokens Matter
Consistency at Scale
Without tokens, a SaaS product with 50+ screens inevitably develops color drift. One developer uses #3b82f6 for the primary button, another uses #2563eb, and a third uses Tailwind's blue-500 (which is #3b82f6 but they don't know that). After six months, you have five shades of blue that are all supposed to be "primary."
Tokens eliminate this. There's one primary color value. Everyone references it. The design stays consistent no matter how large the team or codebase grows.
Rebranding in Minutes, Not Months
When your company rebrands, or when an agency needs to customize a template for a client, tokens let you change the entire visual identity by updating a handful of values. Without tokens, rebranding means searching every file for hardcoded colors, spacing values, and font stacks.
The thefrontkit SaaS Starter Kit uses a token-driven color system where changing the primary color in one file updates every button, link, badge, and focus ring across the entire application.
Design-to-Code Parity
Tokens bridge the gap between Figma and code. When designers and developers use the same token names, there's no translation layer. The Figma mockup says color-primary and the code says color-primary. No ambiguity, no mismatched values.
For a detailed workflow, see The Figma-to-Code Workflow That Actually Works.
Multi-Platform Support
If your product spans web, iOS, Android, and email, tokens give you one source that compiles to each platform's format: CSS custom properties, Swift constants, Kotlin values, or inline styles. Tools like Style Dictionary and Tokens Studio handle this compilation.
Types of Design Tokens
Primitive Tokens (Global Tokens)
The raw palette. These define every possible value in your system, named by what they are, not how they're used.
/* Primitive color tokens */
--blue-50: #eff6ff;
--blue-100: #dbeafe;
--blue-500: #3b82f6;
--blue-600: #2563eb;
--blue-700: #1d4ed8;
--gray-50: #f9fafb;
--gray-100: #f3f4f6;
--gray-900: #111827;
/* Primitive spacing tokens */
--spacing-1: 0.25rem;
--spacing-2: 0.5rem;
--spacing-4: 1rem;
--spacing-6: 1.5rem;
--spacing-8: 2rem;
Semantic Tokens (Alias Tokens)
These map primitive tokens to their purpose. They describe how a value is used, not what it is.
/* Semantic color tokens */
--color-primary: var(--blue-600);
--color-primary-hover: var(--blue-700);
--color-background: var(--gray-50);
--color-surface: white;
--color-text: var(--gray-900);
--color-text-muted: var(--gray-500);
--color-border: var(--gray-200);
--color-destructive: var(--red-600);
/* Semantic spacing tokens */
--spacing-page-padding: var(--spacing-6);
--spacing-card-padding: var(--spacing-4);
--spacing-input-padding-x: var(--spacing-3);
Component Tokens
These are specific to a single component. Most teams don't need this level of granularity unless they're building a public design system.
/* Component-level tokens (optional) */
--button-padding-x: var(--spacing-4);
--button-padding-y: var(--spacing-2);
--button-border-radius: var(--radius-md);
--button-font-size: var(--text-sm);
The practical recommendation: Start with primitives and semantics. Add component tokens only if you have a dedicated design systems team or you're building a public library.
Implementing Design Tokens in Tailwind CSS
Tailwind CSS and design tokens work naturally together. Tailwind's theme configuration is essentially a token system.
Step 1: Define Tokens as CSS Custom Properties
/* app/globals.css */
@layer base {
:root {
--color-primary: 37 99 235; /* blue-600 in RGB */
--color-primary-hover: 29 78 216; /* blue-700 */
--color-background: 249 250 251; /* gray-50 */
--color-surface: 255 255 255;
--color-text: 17 24 39; /* gray-900 */
--color-text-muted: 107 114 128; /* gray-500 */
--color-border: 229 231 235; /* gray-200 */
--color-destructive: 220 38 38; /* red-600 */
--radius-sm: 0.25rem;
--radius-md: 0.375rem;
--radius-lg: 0.5rem;
}
.dark {
--color-primary: 96 165 250; /* blue-400 */
--color-primary-hover: 147 197 253;/* blue-300 */
--color-background: 17 24 39; /* gray-900 */
--color-surface: 31 41 55; /* gray-800 */
--color-text: 249 250 251; /* gray-50 */
--color-text-muted: 156 163 175; /* gray-400 */
--color-border: 55 65 81; /* gray-700 */
--color-destructive: 248 113 113; /* red-400 */
}
}
Step 2: Map Tokens to Tailwind Theme
// tailwind.config.ts
export default {
theme: {
extend: {
colors: {
primary: {
DEFAULT: 'rgb(var(--color-primary) / <alpha-value>)',
hover: 'rgb(var(--color-primary-hover) / <alpha-value>)',
},
background: 'rgb(var(--color-background) / <alpha-value>)',
surface: 'rgb(var(--color-surface) / <alpha-value>)',
foreground: 'rgb(var(--color-text) / <alpha-value>)',
muted: 'rgb(var(--color-text-muted) / <alpha-value>)',
border: 'rgb(var(--color-border) / <alpha-value>)',
destructive: 'rgb(var(--color-destructive) / <alpha-value>)',
},
borderRadius: {
sm: 'var(--radius-sm)',
md: 'var(--radius-md)',
lg: 'var(--radius-lg)',
},
},
},
};
Step 3: Use Tokens in Components
function Button({ children, variant = 'primary' }) {
return (
<button
className={cn(
'rounded-md px-4 py-2 text-sm font-medium transition-colors',
variant === 'primary' && 'bg-primary text-white hover:bg-primary-hover',
variant === 'destructive' && 'bg-destructive text-white',
variant === 'outline' && 'border border-border text-foreground hover:bg-surface'
)}
>
{children}
</button>
);
}
Now bg-primary resolves to your CSS custom property. Change --color-primary in one place and every button, link, and focus ring updates.
For a comprehensive walkthrough, see How to Build a Design Token System with Tailwind CSS.
Design Tokens and Dark Mode
Tokens make dark mode straightforward. Instead of writing conditional styles in every component, you redefine semantic tokens under a .dark class or prefers-color-scheme media query.
:root {
--color-background: 255 255 255;
--color-text: 17 24 39;
}
.dark {
--color-background: 17 24 39;
--color-text: 249 250 251;
}
Every component that uses bg-background and text-foreground automatically adapts. No component-level dark mode logic needed. This is how shadcn/ui and the thefrontkit SaaS Starter Kit handle theming.
Design Tokens and Accessibility
Tokens play a direct role in meeting WCAG AA color contrast requirements. When your colors are centralized in tokens, you can:
- Audit once, fix everywhere. Check contrast ratios for your token pairs (text color on background color). If a pair fails, fix the token and every instance is fixed.
- Prevent regressions. New components automatically inherit accessible color pairings if they use the correct semantic tokens.
- Support high contrast mode. Define a high-contrast token set that maps semantic tokens to maximum-contrast values.
/* High contrast override */
.high-contrast {
--color-text: 0 0 0;
--color-background: 255 255 255;
--color-primary: 0 0 180;
--color-border: 0 0 0;
}
For the full WCAG AA requirements, see What Is WCAG 2.1 AA? and WCAG AA Checklist for Web Apps.
Token Naming Conventions
Good token names are self-documenting. Here are the patterns that scale:
Color Tokens
color-{purpose} → color-primary, color-destructive
color-{purpose}-{variant} → color-primary-hover, color-primary-foreground
color-{element} → color-background, color-surface, color-border
color-{element}-{variant} → color-background-muted, color-border-strong
Spacing Tokens
spacing-{scale} → spacing-1, spacing-2, spacing-4, spacing-8
spacing-{context} → spacing-page, spacing-card, spacing-inline
Typography Tokens
font-{property}-{size} → font-size-sm, font-size-base, font-size-lg
font-{property}-{weight} → font-weight-normal, font-weight-medium, font-weight-bold
Avoid These Naming Mistakes
- Don't name tokens by color:
color-bluebreaks when your brand changes to purple. Usecolor-primary. - Don't use component names in global tokens:
button-bgis a component token, not a semantic token. Usecolor-primaryand let the button reference it. - Don't mix naming conventions: Pick
camelCase,kebab-case, orsnake_caseand stick with it across the entire system.
Tools for Managing Design Tokens
Figma-Side
- Figma Variables (native): Built into Figma. Supports color, number, string, and boolean tokens with modes (light/dark).
- Tokens Studio for Figma: More powerful than native variables. Supports multi-file token sets, theming, and direct sync to code via GitHub.
Code-Side
- CSS Custom Properties: The simplest approach. No build tool needed. Works everywhere.
- Tailwind CSS theme: Extends CSS custom properties with Tailwind's utility class system.
- Style Dictionary (by Amazon): Transforms tokens from a JSON source into CSS, SCSS, iOS, Android, and other platform formats.
- Panda CSS: CSS-in-JS with built-in token support. Compiles to atomic CSS at build time.
Sync Tools
- Tokens Studio + GitHub: Edit tokens in Figma, push to a GitHub repo, CI generates platform code.
- Specify: SaaS tool that syncs design tokens between Figma and code repositories.
Common Mistakes with Design Tokens
1. Too Many Tokens Too Early
Starting with 300 tokens before you have 10 components is over-engineering. Start with color, spacing, border-radius, and typography tokens. Add more as real components demand them.
2. Skipping the Semantic Layer
Jumping from primitive tokens (blue-600) directly to components creates the same problem as hardcoded values. If you decide to change your primary color from blue to indigo, you have to update every component that references blue-600.
Always create semantic tokens (color-primary) that alias your primitives.
3. Not Documenting Token Purpose
A token named --color-accent means different things to different developers unless you document what "accent" means in your system. Add comments or maintain a token reference page.
4. Inconsistent Tokens Between Figma and Code
If the Figma file uses primary/500 but the code uses --color-primary, designers and developers are speaking different languages. Align the naming convention across tools.
Getting Started with Design Tokens
If you're starting a new project, the fastest path is to use a kit that already has a token system in place:
-
The thefrontkit SaaS Starter Kit ships with a complete token system: CSS custom properties mapped to Tailwind theme values, with a matching Figma file. Change the tokens and the entire UI updates.
-
shadcn/ui uses CSS custom properties for all colors, with built-in support for light and dark themes.
-
If you're building from scratch, start with the pattern above: CSS custom properties in
:rootand.dark, mapped to Tailwind's theme config. Begin with 20-30 semantic tokens and expand as needed.
For the complete implementation guide, see How to Build a Design Token System with Tailwind CSS. For how tokens keep a growing product visually cohesive, see How Design Tokens Keep Your SaaS UI Cohesive.
Start with a token-driven foundation: View SaaS Starter Kit | View AI UX Kit | Browse all templates