Building Design Tokens: From Figma to Code

Jessica Cheng

Jessica Cheng

This guide shows you how to build and implement design tokens using Figma Variables, then translate them into code with Next.js, TypeScript, and Tailwind CSS.


What Are Design Tokens?

Tokens are essentially labels for design choices. Instead of scattering actual values throughout your codebase, you create a shared vocabulary. Designers and developers both point to the same name.

The Two-Part Structure

  • An identifier - something readable like brand-primary
  • An actual value - which could be a color hex, pixel measurement, font family, or even reference another token
The Two-Part Structure

Why Design Tokens Matter

Consistency at Scale

The same design values are used across all platforms, products, and teams. No more visual inconsistencies or "close enough" colors.

Faster Development

Developers use pre-defined values instead of making design decisions in code. Components ship faster with fewer design review cycles.

Effortless Updates

Rebrand your entire product by updating a handful of token values. What used to take weeks now takes minutes.

Multi-Platform Support

Define once, use everywhere. Your tokens work on web, iOS, Android, and any future platform.

Theming Built-In

Switch between light mode, dark mode, or brand variations by swapping token values, no component changes needed.


When to Use Design Tokens

Design tokens are most valuable when:

  • You're building products across multiple platforms (web, iOS, Android)
  • Your product needs theming (dark mode, brand variations, white-labeling)
  • Multiple teams work on the same product
  • You plan to scale or evolve your design system
  • Design-to-development handoff takes too long
  • You're experiencing visual inconsistencies across your product

Understanding Token Hierarchy

Professional design systems organize tokens in three tiers. This structure enables flexibility, theming, and clear communication between designers and developers.

Tier 1: Primitive Tokens

Raw values with no context, create your palette of options.

Primitive Tokens

Tier 2: Semantic Tokens

Meaningful names that reference primitives, conveying purpose.

Semantic Tokens

Tier 3: Component Tokens

Component-specific tokens that reference semantic tokens.

Component Tokens

Token Categories

Design tokens organize your visual language into structured categories. Here are the essential token types for modern design systems:

Color Tokens

Brand colors, neutral scales, semantic colors, and UI palettes

  • Brand colors (buttons, links, key actions)
  • Neutral grays (text, backgrounds, borders)
  • Semantic colors (success, error, warning)

Typography Tokens

Font families, sizes, weights, and line heights

  • Font families (sans, serif, mono)
  • Font sizes (xs through 9xl)
  • Font weights (400, 500, 600, 700)

Spacing Tokens

Padding, margins, gaps, and layout spacing values

  • Padding and margins (components)
  • Gaps (flex, grid layouts)
  • Width and height (elements)

Border Radius Tokens

Corner rounding from sharp edges to perfect circles

  • Small (2-4px): buttons, inputs
  • Medium (6-8px): cards, dropdowns
  • Full: pills, avatars

Shadow Tokens

Elevation and depth for visual hierarchy

  • Small: cards above surface
  • Medium: dropdowns, tooltips
  • Large: modals, overlays

Motion Tokens

Animation timing, easing, and duration values

  • Duration (fast, normal, slow)
  • Easing (ease-in, ease-out)
  • Delays (transitions, animations)

Naming Convention

  1. Category
    The token type (color, spacing, typography, etc.)
  2. Property
    What it affects (background, text, border, padding, etc.)
  3. Variant
    The specific use case (primary, secondary, error, success, etc.)
  4. State
    Optional interaction state (hover, active, disabled, etc.)
Naming Convention

Creating Tokens in Figma

Figma Variables are built for design tokens. Here's how to set up a professional system.

Step 1: Create Primitive Colors

Create Collection: Primitives/Colors

Build your foundational color palette with full shade scales (50, 100, 200...900, 950). For each color family, like primary, warning, or neutral, create variables from primary-50 (lightest) to primary-950 (darkest). These raw values have no semantic meaning yet, they're just your color toolkit waiting to be assigned purpose.

Figma Setup

Step 2: Create Semantic Colors

Create Collection: Semantic/Colors

Instead of using raw hex values, assign primitives to semantic tokens based on their purpose. For example, set color-primary to reference primary-600, and color-error to reference warning-600. This creates a meaningful layer between design intent and actual values.

Figma Setup

Step 3: Enable Theming

Add new variable mode: Dark

In your Semantic/Colors collection, add a new mode called "Dark". Now each semantic token can reference different primitives per mode. For example, color-primary might reference primary-600 in Light mode but primary-200 in Dark mode for better contrast on dark backgrounds.

Figma Setup

Implementing design tokens in code

Now let's translate Figma tokens into your Next.js project with Tailwind CSS. The simplest and most maintainable approach is to define your design tokens directly in your CSS using Tailwind's @theme directive.

Let's implement the three-tier token system in Tailwind CSS. Here's when to use each approach:

  • Reference Tokens: Use @theme to override Tailwind's defaults (e.g., --color-blue-500)
  • Semantic Tokens: Use @layer base with theme() function for custom names (e.g., --color-primary)
  • Component Tokens: Use @layer base to reference semantic/theme tokens (most projects skip this layer)

1. Reference Tokens (Override Tailwind Defaults)

Use the @theme directive to override Tailwind's default color scales, spacing, and typography. This is the official approach from the Tailwind CSS documentation.

These tokens automatically work with Tailwind's utility classes. Use bg-blue-500 for backgrounds, text-gray-900 for text, border-blue-200 for borders. Complete scales (50-950) give you natural progressions for hover states, active states, and visual hierarchy.

/* globals.css */
@import "tailwindcss";

@theme {
  /* Reference Tokens - Your color palette */
  
  /* Blue scale - Primary brand color */
  --color-blue-50: #eff6ff;
  --color-blue-100: #dbeafe;
  --color-blue-200: #bfdbfe;
  --color-blue-300: #93c5fd;
  --color-blue-400: #60a5fa;
  --color-blue-500: #3b82f6;
  --color-blue-600: #2563eb;
  --color-blue-700: #1d4ed8;
  --color-blue-800: #1e40af;
  --color-blue-900: #1e3a8a;
  --color-blue-950: #172554;
  
  /* Gray scale - UI colors */
  --color-gray-50: #f9fafb;
  --color-gray-100: #f3f4f6;
  --color-gray-200: #e5e7eb;
  --color-gray-300: #d1d5db;
  --color-gray-400: #9ca3af;
  --color-gray-500: #6b7280;
  --color-gray-600: #4b5563;
  --color-gray-700: #374151;
  --color-gray-800: #1f2937;
  --color-gray-900: #111827;
  --color-gray-950: #030712;
}

2. Semantic Tokens (Custom CSS Properties)

Important: Tailwind's @theme directive only accepts specific token names (like --color-blue-500). For semantic tokens with custom names like --color-primary, use @layer base with CSS custom properties that reference your theme tokens via the theme() function:

These semantic tokens can be used with the var() function in custom CSS or with Tailwind's arbitrary values: bg-[var(--color-primary)]. The theme() function ensures your semantic tokens always reference the correct values from your @theme configuration.

/* globals.css */
@import "tailwindcss";

@theme {
  /* Reference tokens with complete scales (shown above) */
  --color-blue-50: #eff6ff;
  --color-blue-500: #3b82f6;
  --color-blue-600: #2563eb;
  --color-blue-950: #172554;
  /* ... all shades from 50-950 */
}

/* Semantic Tokens - Use CSS custom properties */
@layer base {
  :root {
    /* Semantic color tokens */
    --color-primary: theme(colors.blue.500);
    --color-primary-hover: theme(colors.blue.600);
    --color-primary-light: theme(colors.blue.50);
    --color-primary-dark: theme(colors.blue.900);
    
    /* Semantic text colors */
    --color-text-primary: theme(colors.gray.900);
    --color-text-secondary: theme(colors.gray.600);
    --color-text-muted: theme(colors.gray.400);
    
    /* Semantic background colors */
    --color-bg-primary: theme(colors.gray.50);
    --color-bg-secondary: theme(colors.gray.100);
  }
  
  [data-theme="dark"] {
    /* Override semantic tokens for dark mode */
    --color-primary: theme(colors.blue.400);
    --color-text-primary: theme(colors.gray.50);
    --color-bg-primary: theme(colors.gray.900);
  }
}

3. Component Tokens

Component tokens follow the same pattern as semantic tokens, use @layer base with the theme() function to reference your base or semantic tokens:

Tailwind v4 automatically converts these CSS custom properties into utility classes: bg-button-bg-primary, px-button-padding-x. The --button-bg-primary custom property becomes bg-button-bg-primary class. Notice how component tokens can reference semantic tokens (var(--color-primary)) or theme values directly (theme(colors.white)).

/* globals.css */
@import "tailwindcss";

@theme {
  /* Reference tokens */
  --color-blue-500: #3b82f6;
  --color-blue-600: #2563eb;
  /* ... */
}

/* Semantic Tokens */
@layer base {
  :root {
    --color-primary: theme(colors.blue.500);
    --color-primary-hover: theme(colors.blue.600);
  }
}

/* Component Tokens */
@layer base {
  :root {
    /* Button component tokens */
    --button-bg-primary: var(--color-primary);
    --button-bg-primary-hover: var(--color-primary-hover);
    --button-text-primary: theme(colors.white);
    --button-padding-x: theme(spacing.6);
    --button-padding-y: theme(spacing.2);
    --button-radius: theme(borderRadius.md);
    
    /* Card component tokens */
    --card-background: theme(colors.white);
    --card-padding: theme(spacing.6);
    --card-shadow: theme(boxShadow.lg);
  }
}

Building Components with Tokens

Here's a button component using design tokens with shadcn/ui patterns:

'use client'

import * as React from 'react'
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'

import { cn } from '@/lib/utils'

const buttonVariants = cva(
  'inline-flex items-center justify-center gap-2 text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-50',
  {
    variants: {
      variant: {
        default: 'bg-button-bg-primary text-button-text-primary hover:bg-button-bg-primary-hover rounded-button-radius px-button-padding-x py-button-padding-y',
        secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80 rounded-md',
        outline: 'border-2 border-input bg-background hover:bg-accent hover:text-accent-foreground rounded-md',
        ghost: 'hover:bg-accent hover:text-accent-foreground rounded-md',
      },
      size: {
        default: 'h-10 px-4 py-2',
        sm: 'h-9 px-3 text-xs',
        lg: 'h-11 px-8',
        icon: 'h-10 w-10',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'default',
    },
  }
)

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot : 'button'
    return (
      <Comp
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    )
  }
)
Button.displayName = 'Button'

export { Button, buttonVariants }

Component Preview

Here's how the button looks using these component tokens:

Preview of the Button

How tokens cascade:

1.
bg-button-bg-primary

Component token in the code

2.
--color-primary

Semantic token with meaning

3.
#3b82f6

Reference token with actual value


Have Questions?

Building design systems can be complex. If you have questions about implementing design tokens in your project or need help getting started, let me know!

Get in Touch
Contact 1
Contact 2
Contact 6
Contact 7

Let's make something users will love!

If you're looking for a product designer who can bridge the gap between design and code, I'm here to help!