Style Dictionary and Token Tooling
The Problem Style Dictionary Solves
You have your design tokens in a JSON file. Great. Now what? Your web team needs CSS custom properties. Your iOS team needs Swift constants. Your Android team needs XML resources. Your legacy codebase needs SCSS variables. Are you going to manually maintain four copies of the same data?
That is exactly what Style Dictionary automates. It reads your token source files (JSON, YAML, or JS), runs a series of transforms on them, and outputs platform-specific formats. One input, many outputs, zero manual sync.
Style Dictionary is a compiler for design decisions. Just like a C compiler takes one source file and outputs x86, ARM, and WASM binaries, Style Dictionary takes one token definition and outputs CSS, Swift, Kotlin, and SCSS. You write your tokens once in a platform-agnostic format, and the compiler handles the rest.
Setting Up Style Dictionary
Let us build a real pipeline from scratch. Start with installing Style Dictionary:
npm install style-dictionary
Create a token source file at tokens/color.json:
{
"color": {
"brand": {
"primary": {
"$type": "color",
"$value": "#6366f1"
},
"secondary": {
"$type": "color",
"$value": "#ec4899"
}
},
"neutral": {
"50": { "$type": "color", "$value": "#f9fafb" },
"200": { "$type": "color", "$value": "#e5e7eb" },
"700": { "$type": "color", "$value": "#374151" },
"900": { "$type": "color", "$value": "#111827" }
}
}
}
Create the configuration file style-dictionary.config.mjs:
export default {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [{
destination: 'tokens.css',
format: 'css/variables',
options: {
selector: ':root'
}
}]
},
scss: {
transformGroup: 'scss',
buildPath: 'build/scss/',
files: [{
destination: '_tokens.scss',
format: 'scss/variables'
}]
},
js: {
transformGroup: 'js',
buildPath: 'build/js/',
files: [{
destination: 'tokens.js',
format: 'javascript/es6'
}]
},
ts: {
transformGroup: 'js',
buildPath: 'build/ts/',
files: [{
destination: 'tokens.ts',
format: 'typescript/es6-declarations'
}]
}
}
}
Run the build:
npx style-dictionary build
This generates:
/* build/css/tokens.css */
:root {
--color-brand-primary: #6366f1;
--color-brand-secondary: #ec4899;
--color-neutral-50: #f9fafb;
--color-neutral-200: #e5e7eb;
--color-neutral-700: #374151;
--color-neutral-900: #111827;
}
// build/scss/_tokens.scss
$color-brand-primary: #6366f1;
$color-brand-secondary: #ec4899;
$color-neutral-50: #f9fafb;
// build/js/tokens.js
export const ColorBrandPrimary = "#6366f1";
export const ColorBrandSecondary = "#ec4899";
The Transform Pipeline
Style Dictionary processes every token through a pipeline of transforms before writing output. Understanding this pipeline is key to customizing it.
Transforms in Detail
Transforms modify individual token properties. There are three types:
// Name transform: changes the token's name
// Input: color.brand.primary
// Output (CSS): color-brand-primary
// Output (JS): ColorBrandPrimary
// Value transform: changes the token's value
// Input: #6366f1
// Output (CSS): #6366f1 (unchanged)
// Output (iOS): UIColor(red: 0.39, green: 0.40, blue: 0.95, alpha: 1.0)
// Attribute transform: adds metadata to the token
// Input: { value: "#6366f1" }
// Output: { value: "#6366f1", attributes: { category: "color", type: "brand" } }
Style Dictionary ships with built-in transform groups for common platforms:
// 'css' transform group applies:
// - attribute/cti (adds CTI attributes)
// - name/kebab (color-brand-primary)
// - time/seconds (200ms → 0.2s)
// - size/rem (16px → 1rem)
// - color/css (normalizes color formats)
// 'js' transform group applies:
// - attribute/cti
// - name/pascal (ColorBrandPrimary)
// - size/rem
// - color/hex (normalizes to hex)
Custom Transforms
Built-in transforms handle most cases, but real projects need custom ones. Here is how you register a custom transform that converts hex colors to OKLCH:
import StyleDictionary from 'style-dictionary';
StyleDictionary.registerTransform({
name: 'color/oklch',
type: 'value',
filter: (token) => token.$type === 'color',
transform: (token) => {
return hexToOklch(token.$value);
}
});
StyleDictionary.registerTransformGroup({
name: 'custom/css',
transforms: [
'attribute/cti',
'name/kebab',
'time/seconds',
'size/rem',
'color/oklch' // our custom transform instead of color/css
]
});
Now you can use it in your config:
export default {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'custom/css',
buildPath: 'build/css/',
files: [{
destination: 'tokens.css',
format: 'css/variables'
}]
}
}
};
Custom Formats
You can also create entirely custom output formats. Suppose you want to generate a TypeScript object with proper types:
StyleDictionary.registerFormat({
name: 'typescript/tokens',
format: ({ dictionary }) => {
const tokens = dictionary.allTokens.map(token =>
` '${token.name}': '${token.value}'`
).join(',\n');
return `export const tokens = {\n${tokens}\n} as const;\n\nexport type Token = keyof typeof tokens;\n`;
}
});
Output:
export const tokens = {
'color-brand-primary': '#6366f1',
'color-brand-secondary': '#ec4899',
'color-neutral-50': '#f9fafb'
} as const;
export type Token = keyof typeof tokens;
When writing custom transforms, the filter function runs before transform. If your filter checks token.$type === 'color' but your tokens do not use the $type field (maybe they use type or infer type from the path), the filter will never match and your transform silently does nothing. Always verify your filter matches the shape of your actual token data.
The W3C DTCG Token Format
The W3C Design Tokens Community Group is standardizing how tokens are defined. Style Dictionary v4 supports this format natively. Here is what makes DTCG different from ad-hoc JSON:
{
"Brand Blue": {
"$type": "color",
"$value": "#6366f1",
"$description": "Primary brand color used across all products"
},
"Body Text": {
"$type": "typography",
"$value": {
"fontFamily": "Inter, system-ui, sans-serif",
"fontSize": "16px",
"fontWeight": 400,
"lineHeight": 1.5,
"letterSpacing": "0"
}
},
"Card Shadow": {
"$type": "shadow",
"$value": {
"color": "#00000014",
"offsetX": "0",
"offsetY": "4px",
"blur": "6px",
"spread": "0"
}
},
"Button Radius": {
"$type": "dimension",
"$value": "6px"
},
"Fade In": {
"$type": "duration",
"$value": "200ms"
}
}
The $type field is what makes this format powerful — it tells tools exactly what kind of value this is, enabling type-safe transforms and validation. A tool can verify that a color token contains a valid color value, a dimension token contains a valid length, and so on.
- 1DTCG uses $ prefix for metadata: $type, $value, $description
- 2Composite types (typography, shadow) use objects as $value
- 3References use curly braces: { $value: '{color.brand.primary}' }
- 4Groups are plain keys without $ prefix — the parser distinguishes groups from tokens by checking for $value
The Figma-to-Code Pipeline
Most design systems start in Figma. The question is: how do you get tokens from Figma into your codebase without manual copy-paste?
The key tools in this pipeline:
Figma Tokens Studio (formerly Figma Tokens) is the most popular plugin. It stores tokens in a JSON format that is compatible with Style Dictionary. You can sync tokens to a GitHub repo, making the pipeline fully automated:
- Designer updates a color in Figma Tokens Studio
- Plugin commits the change to a tokens branch in GitHub
- CI runs Style Dictionary build
- PR is created with the updated CSS/SCSS/JS output
- Developer reviews and merges
Figma Variables REST API is Figma's native approach. Since 2023, Figma has first-party Variables that can be exported via their REST API. This is less feature-rich than Tokens Studio but has no plugin dependency.
Alternatives to Style Dictionary
Style Dictionary is the most established tool, but it is not the only option.
| Tool | Format | Strengths | Trade-offs |
|---|---|---|---|
| Style Dictionary | JSON (DTCG support in v4) | Massive ecosystem, extensible transforms, multi-platform | Config-heavy for simple projects, learning curve for custom transforms |
| Cobalt UI | W3C DTCG native | DTCG-first, modern ESM, fast builds, P3 color support | Smaller ecosystem, fewer built-in transforms |
| Theo (Salesforce) | YAML or JSON | Pioneer in token tooling, simple API | Maintenance mode, limited platform support |
| Tokens Studio | Figma plugin + JSON | Tight Figma integration, visual editor for tokens | Figma-dependent, limited transform customization |
When to choose Cobalt UI over Style Dictionary
Cobalt UI is worth considering if you are starting a new project in 2024+. It was built from the ground up for the W3C DTCG spec, supports P3 wide-gamut colors natively, and outputs modern CSS (OKLCH, color-mix). Style Dictionary v4 added DTCG support, but it is retrofitted onto the v3 architecture. If your project is already using Style Dictionary, there is no reason to migrate. If you are starting fresh and your tokens are exclusively DTCG format, Cobalt UI has a cleaner developer experience.
| What developers do | What they should do |
|---|---|
| Manually keeping CSS and SCSS token files in sync Manual sync always drifts — someone updates CSS and forgets SCSS, and now platforms disagree on values | Use Style Dictionary to generate all outputs from a single source |
| Running Style Dictionary only in local dev Local-only builds mean developers can forget to rebuild after token changes, shipping stale values | Run it in CI so every build generates fresh tokens |
| Using path-based type inference instead of explicit $type Path inference is fragile — renaming a group can break transforms. Explicit types are self-documenting and reliable | Always set $type on tokens in DTCG format |