Token Tooling Ecosystem (Style Dictionary, Storybook)
Master the pipelines, formats, and living-documentation tools that transform raw design tokens into a single source of truth across every platform.
7 min read
The full lesson
Design tokens are only as powerful as the tools that move them from Figma into production CSS, iOS Swift, Android Kotlin, and every other platform. Without automation, tokens drift. A designer updates a color in Figma, nothing propagates, and your “single source of truth” quietly becomes three slightly different sources of truth.
The token tooling ecosystem — built around Style Dictionary, Storybook, and the W3C DTCG standard — exists to close that gap permanently.
This lesson walks through the full stack: the token format that should govern your files, the transformation pipeline that converts them, and the documentation layer that makes them usable by every team member.
Why Format Standardization Comes First
Before any tool can help you, every token needs to speak the same language. The W3C Design Token Community Group (DTCG) published a stable JSON format in 2024. It is now the right default for new systems. The shape is straightforward:
{
"color-brand-primary": {
"$value": "#0057FF",
"$type": "color",
"$description": "Primary interactive brand color"
}
}
The dollar-prefixed keys — $value, $type, $description — signal that this file uses DTCG format, not an older proprietary schema. Style Dictionary v4+ (released 2024) supports DTCG natively. So do Theo, Supernova, and Token Transformer.
The DTCG spec defines standard $type values: color, dimension, fontFamily, fontWeight, duration, cubicBezier, number, strokeStyle, border, transition, shadow, gradient, and typography. Using standard types lets tools make smart decisions without extra configuration. They know a duration token should output in milliseconds for CSS and in seconds for iOS.
Three-Tier Token Architecture
The format determines structure. The architecture determines meaning. Modern practice uses a three-tier hierarchy:
| Tier | Also called | Example name | Example value |
|---|---|---|---|
| Primitive | Global / raw | color-blue-500 | oklch(55% 0.2 250) |
| Semantic | Alias / decision | color-interactive-default | {color-blue-500} |
| Component | Specific | button-background-default | {color-interactive-default} |
Primitives are your palette — every possible value your brand can use. Semantics express intent without encoding a specific value; they reference primitives. Component tokens optionally exist for high-specificity overrides.
A common outdated habit is to skip semantics and use flat color-name tokens directly in components — for example, background: var(--blue-500). That works fine until you add dark mode or a second brand. Then you have to hunt down hundreds of component-level references. With semantic tokens, you remap color-interactive-default once, and every consuming component updates automatically.
Do
Name semantic tokens by role and state: color-surface-raised, color-text-disabled, color-feedback-error. Reference primitives through semantics so theming is a one-layer swap.
Don't
Name semantic tokens after their resolved value: color-blue-primary, color-light-grey. When you rebrand or add dark mode, these names become actively misleading and every reference must be audited.
Style Dictionary: The Transformation Engine
Style Dictionary (Amazon, open-source) is the most widely adopted token build tool. It takes token JSON as input and emits platform-specific output: CSS custom properties, SCSS variables, Swift enum values, Kotlin object declarations, JavaScript/TypeScript constants, and more.
A minimal project structure:
tokens/
primitives/
color.json
dimension.json
semantic/
color.json
typography.json
config.js
A Style Dictionary v4 config using DTCG tokens:
import StyleDictionary from 'style-dictionary';
const sd = new StyleDictionary({
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
prefix: 'ds',
buildPath: 'dist/css/',
files: [
{
destination: 'variables.css',
format: 'css/variables',
options: { outputReferences: true }
}
]
},
ios: {
transformGroup: 'ios-swift',
buildPath: 'dist/ios/',
files: [
{
destination: 'DesignTokens.swift',
format: 'ios-swift/enum.swift'
}
]
}
}
});
await sd.buildAllPlatforms();
The outputReferences: true option is important. It emits var(--ds-color-interactive-default) referencing var(--ds-color-blue-500) instead of resolving everything to a flat hex value. That preserves the semantic-to-primitive relationship in CSS output — which is what makes CSS-level theming possible through custom property overrides.
Custom Transforms
Style Dictionary’s real power is extensibility. You can register transforms that mutate token values before output. For example, you can convert OKLCH color values to a fallback hex for older iOS targets, or divide a pixel dimension value by 16 to emit rem:
StyleDictionary.registerTransform({
name: 'dimension/remScale',
type: 'value',
filter: token => token.$type === 'dimension',
transform: token => `${parseFloat(token.$value) / 16}rem`
});
Register the transform, add it to a platform’s transforms array, and every dimension token in that platform outputs in rem. This is the modern approach to platform-adaptive tokens — one source, multiple smart outputs.
Theming with Token Sets
For dark mode and multi-brand support, the best practice today is token sets: separate JSON files that contain only the semantic overrides for each theme. The build runs twice — once with the default set, once with the overrides merged on top — producing variables.css and variables-dark.css.
Alternatively, CSS custom property output lets you scope themes to a selector:
:root { --ds-color-surface-default: oklch(99% 0.01 250); }
[data-theme="dark"] { --ds-color-surface-default: oklch(14% 0.01 250); }
Note that dark surfaces should use near-black (roughly #0A0A0A) rather than pure #000000. Pure black creates an unnatural contrast with any element that is not also pure black, and shadow-based elevation becomes invisible. Semantic tokens make this rule easy to enforce — it lives in one token file, not hundreds of component files.
Storybook: Living Token Documentation
Style Dictionary handles the build. Storybook handles communication. A pipeline that emits correct CSS means nothing if designers cannot inspect it, engineers cannot find the right token name, and QA cannot verify that a component uses the right value.
Storybook (v8, 2025–2026) serves as the living documentation layer for the design system. It integrates with tokens in three main ways.
Token Add-ons and Theme Switching
The storybook-design-token add-on parses your compiled CSS custom properties and renders a browsable token inventory panel alongside component stories. Engineers see both the token name and its current resolved value — much faster than reading raw JSON.
For theme verification, a global decorator can inject a data-theme attribute based on a toolbar item. This lets reviewers switch between light and dark themes live in Storybook:
// .storybook/preview.js
export const globalTypes = {
theme: {
name: 'Theme',
defaultValue: 'light',
toolbar: {
icon: 'mirror',
items: ['light', 'dark'],
dynamicTitle: true
}
}
};
export const decorators = [
(Story, context) => {
document.documentElement.setAttribute(
'data-theme',
context.globals.theme
);
return Story();
}
];
Figma Code Connect
Figma Code Connect (GA 2024) maps Figma component variants to Storybook stories. When a developer inspects a component in Figma Dev Mode, they see real code snippets pulled from the connected story — not auto-generated prop guesses. This replaces the outdated workflow of redline PDFs and Zeplin spec documents that drift from the actual implementation.
The setup involves a figma.connect() call in a sidecar file:
import figma from '@figma/code-connect';
import { Button } from './Button';
figma.connect(Button, 'https://figma.com/file/...?node-id=...', {
props: {
variant: figma.enum('Variant', {
Primary: 'primary',
Secondary: 'secondary'
}),
label: figma.string('Label')
},
example: ({ variant, label }) =>
`<Button variant="${variant}">${label}</Button>`
});
This is the “token-driven living handoff” pattern: Figma shows real code, that code uses semantic tokens, and those tokens are the same ones that ran through Style Dictionary. The chain is unbroken.
Automated Accessibility Checks
Storybook’s @storybook/addon-a11y runs Axe checks on every story. Pair this with CI and any token change that accidentally breaks contrast gets caught before it reaches production. The add-on flags WCAG 2.2 AA violations — the current legal baseline — and surfaces them in the Accessibility panel.
Component-level contrast violations are especially easy to introduce through token changes. If a designer updates color-text-disabled to a lighter value, the a11y addon immediately flags any story where that token falls below 4.5:1 against its background.
Automating the Pipeline in CI
The token tooling ecosystem reaches full effectiveness when it runs automatically. A typical pipeline looks like this:
- A designer exports tokens from Figma using the Tokens Studio plugin (DTCG JSON output) and opens a pull request against the token repo.
- Style Dictionary runs in the PR check, building all platform outputs and diffing the result against the previous build.
- The diff is posted as a PR comment: “24 CSS variables changed, 2 new tokens added.”
- Storybook builds and deploys a preview environment where reviewers can inspect every story against the new tokens.
- The a11y addon runs and fails the check if any WCAG 2.2 AA violations are introduced.
- On merge, Style Dictionary publishes updated token packages to npm and the production Storybook deployment updates.
This pipeline means tokens are never manually copied between tools. Token drift becomes a detectable, reviewable event — not a silent accumulation of inconsistency.
Governance: Versioning and Change Management
At scale, the token pipeline needs governance rules as much as technical infrastructure.
Semantic versioning for token packages. Treat breaking token changes — renaming a token, changing a type — as major version bumps. Additive changes (new tokens) are minor. Non-breaking value tweaks (adjusting a shade) are patches. Publish each platform’s output as a versioned npm package so consuming teams can pin to a version and upgrade intentionally.
Deprecation before deletion. Add a $deprecated: true flag to tokens being phased out. Style Dictionary can transform this into a CSS comment or even a console warning in development builds. Teams get a migration window. You avoid a breaking change with no notice.
Token request workflow. Make the process for adding new tokens explicit: a token proposal issue, a design review confirming no existing semantic token can serve the need, and a PR that adds it to the DTCG source JSON. Without this gate, token files accumulate near-duplicate tokens that nobody can confidently deprecate.
The Full Ecosystem at a Glance
| Layer | Tool | Responsibility |
|---|---|---|
| Source | DTCG JSON (Tokens Studio export) | Single source of truth |
| Transform | Style Dictionary v4 | Platform-specific output |
| Distribution | npm packages | Versioned, platform-specific delivery |
| Documentation | Storybook + design-token add-on | Living component and token reference |
| Handoff | Figma Code Connect | Design-to-code specification |
| Quality | a11y addon + CI | Automated WCAG 2.2 enforcement |
| Governance | Semantic versioning + deprecation flags | Controlled change management |
No single layer in this stack is optional. Remove any one and you create a gap that human coordination will eventually fail to fill. The ecosystem is the system.