Transforms design tokens into platform-specific formats (CSS, SCSS, iOS Swift, Android XML). Use when setting up multi-platform token pipelines, creating build processes, or managing cross-platform design systems.
Transforms design tokens into platform-specific formats (CSS, Swift, XML) for multi-platform design systems. Use when setting up token pipelines, converting Figma tokens to code, or managing cross-platform design tokens.
/plugin marketplace add dylantarre/design-system-skills/plugin install design-system-skills@design-system-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Set up Style Dictionary to transform design tokens into platform-specific formats. The industry standard for design systems that need to output to web, iOS, Android, and other platforms from a single token source.
| Concept | Purpose | Example |
|---|---|---|
| Token | Design value with metadata | { "value": "#3b82f6", "type": "color" } |
| Transform | Converts token values | color/hex → color/rgb |
| Format | Outputs to file type | CSS variables, Swift, XML |
| Platform | Target environment | web, ios, android |
style-dictionary.config.jsstyle-dictionary buildCopy this checklist when setting up Style Dictionary:
Style Dictionary Setup:
- [ ] Install: `npm install style-dictionary`
- [ ] Create tokens/ directory with source JSON files
- [ ] Create style-dictionary.config.js with source paths and platform outputs
- [ ] Add build script to package.json: `"tokens:build": "style-dictionary build"`
- [ ] Run build and verify output files are generated correctly
npm install style-dictionary
# or
yarn add style-dictionary
tokens/
├── base/
│ ├── colors.json
│ ├── spacing.json
│ └── typography.json
├── semantic/
│ ├── colors.json
│ └── components.json
└── themes/
├── light.json
└── dark.json
build/ # Generated output
├── css/
│ └── variables.css
├── ios/
│ └── StyleDictionary.swift
└── android/
└── colors.xml
style-dictionary.config.js
// style-dictionary.config.js
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [
{
destination: 'variables.css',
format: 'css/variables',
},
],
},
},
};
// style-dictionary.config.js
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
// Web - CSS Custom Properties
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [
{
destination: 'variables.css',
format: 'css/variables',
options: {
outputReferences: true, // Keep token references
},
},
],
},
// Web - SCSS Variables
scss: {
transformGroup: 'scss',
buildPath: 'build/scss/',
files: [
{
destination: '_variables.scss',
format: 'scss/variables',
},
],
},
// Web - JavaScript/TypeScript
js: {
transformGroup: 'js',
buildPath: 'build/js/',
files: [
{
destination: 'tokens.js',
format: 'javascript/es6',
},
{
destination: 'tokens.d.ts',
format: 'typescript/es6-declarations',
},
],
},
// iOS - Swift
ios: {
transformGroup: 'ios-swift',
buildPath: 'build/ios/',
files: [
{
destination: 'StyleDictionary.swift',
format: 'ios-swift/class.swift',
className: 'StyleDictionary',
},
],
},
// Android - XML Resources
android: {
transformGroup: 'android',
buildPath: 'build/android/',
files: [
{
destination: 'colors.xml',
format: 'android/colors',
filter: { type: 'color' },
},
{
destination: 'dimens.xml',
format: 'android/dimens',
filter: { type: 'dimension' },
},
],
},
},
};
{
"color": {
"primary": {
"$value": "#3b82f6",
"$type": "color",
"$description": "Primary brand color"
},
"secondary": {
"$value": "#64748b",
"$type": "color"
}
},
"spacing": {
"sm": {
"$value": "8px",
"$type": "dimension"
},
"md": {
"$value": "16px",
"$type": "dimension"
}
}
}
{
"color": {
"primary": {
"value": "#3b82f6",
"type": "color",
"comment": "Primary brand color"
}
},
"spacing": {
"sm": { "value": "8px" },
"md": { "value": "16px" }
}
}
{
"color": {
"base": {
"blue": {
"500": { "value": "#3b82f6" }
}
},
"primary": {
"value": "{color.base.blue.500}"
},
"button": {
"background": {
"value": "{color.primary}"
}
}
}
}
// style-dictionary.config.js
const StyleDictionary = require('style-dictionary');
// Transform px to rem
StyleDictionary.registerTransform({
name: 'size/pxToRem',
type: 'value',
matcher: (token) => token.type === 'dimension',
transformer: (token) => {
const px = parseFloat(token.value);
return `${px / 16}rem`;
},
});
// Transform color to OKLCH
StyleDictionary.registerTransform({
name: 'color/oklch',
type: 'value',
matcher: (token) => token.type === 'color',
transformer: (token) => {
// Use a color library like culori
const { formatCss, oklch, parse } = require('culori');
return formatCss(oklch(parse(token.value)));
},
});
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
css: {
transforms: [
'attribute/cti',
'name/cti/kebab',
'size/pxToRem', // Custom
'color/oklch', // Custom
],
buildPath: 'build/css/',
files: [
{
destination: 'variables.css',
format: 'css/variables',
},
],
},
},
};
// Clamp font sizes for fluid typography
StyleDictionary.registerTransform({
name: 'size/fluidType',
type: 'value',
matcher: (token) => token.attributes?.category === 'font' && token.attributes?.type === 'size',
transformer: (token) => {
const min = parseFloat(token.value) * 0.875;
const max = parseFloat(token.value);
return `clamp(${min}rem, 2vw + 1rem, ${max}rem)`;
},
});
// Shadow to CSS format
StyleDictionary.registerTransform({
name: 'shadow/css',
type: 'value',
matcher: (token) => token.type === 'shadow',
transformer: (token) => {
const { x, y, blur, spread, color } = token.value;
return `${x}px ${y}px ${blur}px ${spread}px ${color}`;
},
});
StyleDictionary.registerFormat({
name: 'css/variables-themed',
formatter: ({ dictionary, options }) => {
const lightTokens = dictionary.allTokens
.filter(t => !t.path.includes('dark'))
.map(t => ` --${t.name}: ${t.value};`)
.join('\n');
const darkTokens = dictionary.allTokens
.filter(t => t.path.includes('dark'))
.map(t => {
const name = t.name.replace('dark-', '');
return ` --${name}: ${t.value};`;
})
.join('\n');
return `:root {\n${lightTokens}\n}\n\n[data-theme="dark"] {\n${darkTokens}\n}`;
},
});
StyleDictionary.registerFormat({
name: 'tailwind/config',
formatter: ({ dictionary }) => {
const colors = {};
const spacing = {};
dictionary.allTokens.forEach(token => {
if (token.type === 'color') {
const path = token.path.slice(1).join('-');
colors[path] = token.value;
}
if (token.type === 'dimension' && token.path[0] === 'spacing') {
spacing[token.path[1]] = token.value;
}
});
return `module.exports = {
theme: {
extend: {
colors: ${JSON.stringify(colors, null, 2)},
spacing: ${JSON.stringify(spacing, null, 2)},
},
},
};`;
},
});
tokens/
├── core/
│ ├── colors.json # Primitives (blue-500, gray-100)
│ └── spacing.json
├── semantic/
│ ├── light.json # Semantic mappings for light
│ └── dark.json # Semantic mappings for dark
└── brand/
├── default.json # Default brand
└── partner.json # White-label brand
// style-dictionary.config.js
const themes = ['light', 'dark'];
const brands = ['default', 'partner'];
module.exports = {
source: ['tokens/core/**/*.json'],
platforms: brands.flatMap(brand =>
themes.map(theme => ({
[`css-${brand}-${theme}`]: {
transformGroup: 'css',
buildPath: `build/${brand}/`,
files: [
{
destination: `${theme}.css`,
format: 'css/variables',
filter: (token) =>
token.filePath.includes('core') ||
token.filePath.includes(theme),
},
],
source: [
`tokens/semantic/${theme}.json`,
`tokens/brand/${brand}.json`,
],
},
}))
),
};
{
"scripts": {
"tokens:build": "style-dictionary build",
"tokens:watch": "style-dictionary build --watch",
"tokens:clean": "rm -rf build/",
"prebuild": "npm run tokens:build"
}
}
# 1. Export from Figma Tokens plugin to tokens/figma.json
# 2. Transform with Style Dictionary
npx token-transformer tokens/figma.json tokens/transformed.json
style-dictionary build
# .github/workflows/tokens.yml
name: Build Tokens
on:
push:
paths:
- 'tokens/**'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run tokens:build
- uses: actions/upload-artifact@v4
with:
name: tokens
path: build/
{
"color": {
"primary": {
"value": "#3b82f6",
"type": "color"
}
}
}
:root {
--color-primary: #3b82f6;
}
$color-primary: #3b82f6;
export const ColorPrimary = '#3b82f6';
public class StyleDictionary {
public static let colorPrimary = UIColor(red: 0.231, green: 0.510, blue: 0.965, alpha: 1.0)
}
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<color name="color_primary">#3b82f6</color>
</resources>
| Issue | Solution |
|---|---|
| Circular references | Check token aliases don't loop |
| Token not found | Verify path in reference matches exactly |
| Wrong output format | Check transform group matches platform |
| Missing tokens | Check filter isn't excluding them |
| Stale builds | Run tokens:clean before build |
// style-dictionary.config.js (v4 syntax)
import StyleDictionary from 'style-dictionary';
export default {
source: ['tokens/**/*.json'],
preprocessors: ['tokens-studio'], // For Figma Tokens
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/',
files: [{
destination: 'variables.css',
format: 'css/variables',
}],
},
},
};
# Run with ESM
node --experimental-json-modules ./node_modules/.bin/style-dictionary build