Design Tokens: Bridging the Gap Between Figma and Production
Hardcoding HEX values is technical debt. How to build a multi-platform Design System using JSON tokens and Style Dictionary.
“Can you change the primary blue to a slightly darker blue?”
In a legacy codebase, this request costs $5,000.
Why? Because #3b82f6 is hardcoded in 400 CSS files, 20 JS files, and 5 HTML templates.
In a modern codebase, this request costs $0.
You update the Design Token in Figma, and it propagates to iOS, Android, and Web automatically.
Why Maison Code Discusses This
At Maison Code Paris, we act as the architectural conscience for our clients. We often inherit “modern” stacks that were built without a foundational understanding of scale. We see simple APIs that take 4 seconds to respond because of N+1 query problems, and “Microservices” that cost $5,000/month in idle cloud fees.
We discuss this topic because it represents a critical pivot point in engineering maturity. Implementing this correctly differentiates a fragile MVP from a resilient, enterprise-grade platform that can handle Black Friday traffic without breaking a sweat.
What are Design Tokens?
Design Tokens are the “Atoms” of visual design. They are platform-agnostic key-value pairs.
- Legacy:
color: #000000; - Token:
color: var(--color-foreground);
The Token Hierarchy
We don’t just flatten everything. We use a 3-tier hierarchy to ensure semantic meaning.
1. Primitive Tokens (Global)
Raw values. They should never be used directly in the UI.
blue-500:#3b82f6gray-900:#111827spacer-4:16px
2. Semantic Tokens (Alias): Purpose-driven.
color-primary:{blue-500}color-surface:{gray-900}(Crucial for Dark Mode)spacing-card-padding:{spacer-4}
3. Component Tokens (Specific)
Context-driven overrides.
button-bg-primary:{color-primary}card-bg:{color-surface}input-border-error:{color-destructive}
The Workflow: Figma to Code
We treat Figma as the “Source of Truth” for design, just as we treat Git as the source of truth for code. We use the Variables feature in Figma combined with the “Tokens Studio” plugin.
Step 1: Exporting Tokens
We export tokens.json. This file is the single source of truth.
{
"global": {
"colors": {
"blue": { "500": { "value": "#3b82f6" } }
}
},
"semantic": {
"primary": { "value": "{colors.blue.500}" },
"on-primary": { "value": "{colors.white}" }
}
}
Step 2: Transformations (Style Dictionary)
JSON is useless to iOS (Swift) or Android (XML).
We use Style Dictionary (by Amazon) to transform the JSON into platform-specific artifacts.
The build pipeline (npm run build:tokens) looks like this:
graph LR
Figma[Figma Variables] -->|Plugin| JSON[tokens.json]
JSON -->|CI/CD| SD[Style Dictionary]
SD -->|Transform| CSS[CSS Variables]
SD -->|Transform| TS[Tailwind Config]
SD -->|Transform| Swift[Color.swift]
SD -->|Transform| XML[colors.xml]
Step 3: Consumption in Tailwind
For our Headless Storefront (built with Atomic Design), we map these tokens to Tailwind CSS.
In tailwind.config.js, we do not hardcode values. We read the build artifacts.
// tailwind.config.js
const tokens = require('./build/tokens.js');
module.exports = {
theme: {
colors: {
primary: 'var(--color-primary)', // Maps to CSS var
background: 'var(--color-background)',
},
extend: {
borderRadius: tokens.radius,
fontFamily: tokens.typography,
spacing: tokens.spacing
}
}
}
This means we never write class="bg-[#3b82f6]".
We write class="bg-primary".
If the brand rebrands to Red, we change token primary -> red-500 in Figma.
The entire site updates instantly upon deployment.
Dark Mode Architecture
Dark mode is not about “inverting colors.” It’s about Token Swapping.
We define a light map and a dark map.
They share the same Semantic Names (--color-background), but point to different Primitives.
CSS Implementation
:root {
/* Default (Light) */
--color-background: var(--white);
--color-text: var(--black);
--color-border: var(--gray-200);
}
[data-theme="dark"] {
/* Override */
--color-background: var(--black);
--color-text: var(--white);
--color-border: var(--gray-800);
}
Because Tailwind uses the Semantic Name, the class bg-background works in both modes.
It is White in Light Mode and Black in Dark Mode. No extra classes (dark:bg-black) needed in your React components.
This reduces bundle size significantly.
Multi-Brand Systems (Theming)
For agencies managing multiple storefronts (e.g., GAP, Old Navy, Banana Republic), Token Systems allow you to reuse the same React Codebase.
You simply load a different tokens.css file.
- Gap:
primary = Blue,radius = 4px. - Old Navy:
primary = Navy,radius = 8px. The<Button />component code remains identical:<button className="bg-primary rounded-radius">. This is “White Labeling” at scale.
Typography Tokens
Design tokens aren’t just colors.
- Size:
text-xl->1.25rem - Weight:
font-bold->700 - Line Height:
leading-tight->1.25 - Letter Spacing:
tracking-wide->0.025em
We encode “Typescales” (Major Third, Perfect Fourth) into the tokens to ensure mathematical harmony.
If you manually set font-size: 17px, you break the rhythm.
Tokens enforce the system.
9. Visualizing Tokens: The Storybook Addon
Tokens are abstract. Developers need to see them. We build a custom Storybook Addon that displays all tokens live.
- Color Palette: Grids of color swatches with their token names.
- Typography Scale: Text rendered in each font size.
- Shadows: Boxes showing elevation levels. This serves as the “Living Documentation”. If a developer needs a color, they don’t open Figma. They open Storybook, search “Primary”, and copy the class name.
10. The “Theme Provider” Context
In React, how do you switch themes efficiently? Don’t pass props. Use CSS Variables + Context.
const ThemeContext = createContext({ theme: 'light', toggle: () => {} });
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
useEffect(() => {
document.documentElement.dataset.theme = theme;
}, [theme]);
return <ThemeContext.Provider value={{ theme, setTheme }}>{children}</ThemeContext.Provider>;
}
This updates the data-theme attribute on the <html> tag.
The CSS Variables recalculate instantly.
The React Tree does not re-render (except for the Toggle button itself).
This is crucial for performance.
11. Maintenance and Governance
“With great power comes great responsibility.”
If a Junior Designer seeks to change primary blue, they could break Accessibility compliance across the app.
We implement CI Checks (Style Dictionary Linting) for tokens.
Automated Checks
- Contrast Check: Ensure
on-primarytext has 4.5:1 contrast againstprimarybackground. If not, the build fails. - Naming Convention: Reject
blue-final-v2. Enforceblue-500. - Orphaned Tokens: Warn if a defined token is never used in the UI logic.
12. Token Aliasing for Accessibility
Accessibility isn’t just color contrast. It’s user preference.
Some users need “High Contrast Mode”.
Some users need “Reduced Motion”.
We map tokens to these media queries.
motion-duration: { var(--motion-fast) }
@media (prefers-reduced-motion) { --motion-fast: 0ms; }
Tokenizing motion allows us to respect the user’s wish to turn off animations globally, without rewriting CSS components.
13. Mobile vs Web Tokens
iOS uses Points. Web uses Rem. Android uses DP.
A naive export fails.
We use Style Dictionary Transforms to handle the math.
spacing.4 (16px) -> iOS 16pt -> Android 16dp.
We also handle Naming Conventions:
- Web:
kebab-case(--color-primary) - iOS:
camelCase(colorPrimary) - Android:
snake_case(color_primary) This ensures developers feel at home on their platform.
14. Conclusion
Design Tokens are the “API” between Design and Engineering. They decouple the value (Hex code) from the intent (Primary Color). For a Maison, where brand guidelines are sacred, Design Tokens are the only way to guarantee 100% fidelity across every digital touchpoint. Stop writing CSS. Start writing Systems.