Design Tokens: Uniendo Diseño y Desarrollo
Cómo los design tokens crean una única fuente de verdad para colores, espaciado y tipografía, eliminando la divergencia entre Figma y producción.

Los sistemas de diseño fallan cuando los diseñadores actualizan un color en Figma y los desarrolladores nunca se enteran. O cuando los desarrolladores agregan un nuevo valor de espaciado que no existe en la especificación de diseño. Los design tokens resuelven esto estableciendo una única fuente de verdad: valores independientes de la plataforma que tanto las herramientas como el código consumen.
Un design token es un valor con nombre: color-primary-500: #3B82F6. Ese valor se transforma en propiedades personalizadas de CSS, configuración de Tailwind, constantes Swift para iOS y recursos XML de Android. Cambia el token y todas las plataformas se actualizan.
Cómo se ven los tokens
Los tokens normalmente se almacenan en JSON o YAML, siguiendo la emergente especificación de Design Tokens del W3C.
{
"color": {
"primary": {
"100": { "$value": "#DBEAFE", "$type": "color" },
"300": { "$value": "#93C5FD", "$type": "color" },
"500": { "$value": "#3B82F6", "$type": "color" },
"700": { "$value": "#1D4ED8", "$type": "color" },
"900": { "$value": "#1E3A8A", "$type": "color" }
},
"neutral": {
"50": { "$value": "#F9FAFB", "$type": "color" },
"200": { "$value": "#E5E7EB", "$type": "color" },
"500": { "$value": "#6B7280", "$type": "color" },
"800": { "$value": "#1F2937", "$type": "color" },
"950": { "$value": "#030712", "$type": "color" }
}
},
"spacing": {
"xs": { "$value": "4px", "$type": "dimension" },
"sm": { "$value": "8px", "$type": "dimension" },
"md": { "$value": "16px", "$type": "dimension" },
"lg": { "$value": "24px", "$type": "dimension" },
"xl": { "$value": "32px", "$type": "dimension" },
"2xl": { "$value": "48px", "$type": "dimension" }
},
"font": {
"family": {
"sans": { "$value": "Inter, system-ui, sans-serif", "$type": "fontFamily" },
"mono": { "$value": "JetBrains Mono, monospace", "$type": "fontFamily" }
},
"size": {
"sm": { "$value": "14px", "$type": "dimension" },
"base": { "$value": "16px", "$type": "dimension" },
"lg": { "$value": "18px", "$type": "dimension" },
"xl": { "$value": "20px", "$type": "dimension" },
"2xl": { "$value": "24px", "$type": "dimension" },
"4xl": { "$value": "36px", "$type": "dimension" }
}
}
}Este JSON es la fuente. Todo lo demás se genera a partir de él.
Transformación de tokens con Style Dictionary
Style Dictionary es la herramienta estándar para transformar tokens en salidas específicas de plataforma. Un archivo fuente produce CSS, JavaScript, TypeScript y formatos nativos móviles.
// style-dictionary.config.js
const StyleDictionary = require('style-dictionary');
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'dist/css/',
files: [{
destination: 'tokens.css',
format: 'css/variables',
options: { outputReferences: true },
}],
},
js: {
transformGroup: 'js',
buildPath: 'dist/js/',
files: [{
destination: 'tokens.js',
format: 'javascript/es6',
}],
},
typescript: {
transformGroup: 'js',
buildPath: 'dist/ts/',
files: [{
destination: 'tokens.ts',
format: 'javascript/es6',
}],
},
tailwind: {
transformGroup: 'js',
buildPath: 'dist/tailwind/',
files: [{
destination: 'tailwind-tokens.js',
format: 'javascript/module',
}],
},
},
};Ejecutar style-dictionary build produce estas salidas:
/* dist/css/tokens.css */
:root {
--color-primary-100: #DBEAFE;
--color-primary-300: #93C5FD;
--color-primary-500: #3B82F6;
--color-primary-700: #1D4ED8;
--color-primary-900: #1E3A8A;
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--font-family-sans: Inter, system-ui, sans-serif;
--font-size-base: 16px;
}// dist/ts/tokens.ts
export const ColorPrimary100 = "#DBEAFE";
export const ColorPrimary500 = "#3B82F6";
export const SpacingMd = "16px";
export const FontFamilySans = "Inter, system-ui, sans-serif";Capas de tokens: global, semántica y componente
Los valores crudos como #3B82F6 son tokens globales. Necesitan una capa semántica que describa la intención y una capa de componente que se asigne a elementos específicos de la UI.
{
"color": {
"global": {
"blue-500": { "$value": "#3B82F6" },
"red-500": { "$value": "#EF4444" },
"green-500": { "$value": "#22C55E" },
"gray-800": { "$value": "#1F2937" },
"gray-50": { "$value": "#F9FAFB" }
},
"semantic": {
"action": { "$value": "{color.global.blue-500}" },
"error": { "$value": "{color.global.red-500}" },
"success": { "$value": "{color.global.green-500}" },
"text-primary": { "$value": "{color.global.gray-800}" },
"bg-primary": { "$value": "{color.global.gray-50}" }
},
"component": {
"button-bg": { "$value": "{color.semantic.action}" },
"button-bg-hover": { "$value": "{color.global.blue-700}" },
"alert-error-bg": { "$value": "{color.semantic.error}" },
"input-border": { "$value": "{color.global.gray-300}" }
}
}
}/* ❌ Usar tokens globales directamente en componentes */
.button {
background: var(--color-global-blue-500);
/* ¿Qué pasa cuando el color de marca cambia a morado? */
/* Buscas blue-500 en todo el código */
}
/* ✅ Usar tokens semánticos/de componente */
.button {
background: var(--color-button-bg);
/* Cambio de marca = actualizar un mapeo de token */
}El enfoque de tres capas significa que un cambio de marca requiere modificar solo los mapeos semánticos a globales. Sin cambios en el código de componentes, sin ediciones de archivos CSS.
Modo oscuro mediante alias de tokens
El modo oscuro se vuelve trivial cuando los tokens usan nombres semánticos. Intercambia los valores globales detrás de los tokens semánticos.
{
"color": {
"semantic": {
"text-primary": {
"$value": "{color.global.gray-900}",
"$extensions": {
"dark": "{color.global.gray-100}"
}
},
"bg-primary": {
"$value": "{color.global.white}",
"$extensions": {
"dark": "{color.global.gray-900}"
}
},
"bg-surface": {
"$value": "{color.global.gray-50}",
"$extensions": {
"dark": "{color.global.gray-800}"
}
}
}
}
}/* CSS generado con soporte para modo oscuro */
:root {
--color-text-primary: #111827;
--color-bg-primary: #FFFFFF;
--color-bg-surface: #F9FAFB;
}
@media (prefers-color-scheme: dark) {
:root {
--color-text-primary: #F3F4F6;
--color-bg-primary: #111827;
--color-bg-surface: #1F2937;
}
}
/* O alternancia basada en clases */
[data-theme="dark"] {
--color-text-primary: #F3F4F6;
--color-bg-primary: #111827;
--color-bg-surface: #1F2937;
}Cada componente que usa var(--color-text-primary) se adapta automáticamente al modo oscuro. Sin CSS condicional, sin hojas de estilo específicas por tema, sin alternancia con JavaScript.
Integración de tokens con Tailwind CSS
Los proyectos de Tailwind pueden consumir design tokens generando la configuración de Tailwind a partir de los archivos de tokens.
// tailwind.config.js
const tokens = require('./dist/tailwind/tailwind-tokens');
module.exports = {
theme: {
colors: {
primary: {
100: tokens.ColorPrimary100,
300: tokens.ColorPrimary300,
500: tokens.ColorPrimary500,
700: tokens.ColorPrimary700,
900: tokens.ColorPrimary900,
},
neutral: {
50: tokens.ColorNeutral50,
200: tokens.ColorNeutral200,
500: tokens.ColorNeutral500,
800: tokens.ColorNeutral800,
},
},
spacing: {
xs: tokens.SpacingXs,
sm: tokens.SpacingSm,
md: tokens.SpacingMd,
lg: tokens.SpacingLg,
xl: tokens.SpacingXl,
},
fontFamily: {
sans: [tokens.FontFamilySans],
mono: [tokens.FontFamilyMono],
},
},
};// Components use Tailwind classes backed by tokens
function Card({ title, children }: CardProps) {
return (
<div className="bg-neutral-50 rounded-lg p-lg shadow-sm">
<h3 className="text-primary-900 font-sans text-xl mb-sm">
{title}
</h3>
<div className="text-neutral-800">{children}</div>
</div>
);
}Ahora bg-neutral-50 se resuelve al valor del token, no a un color codificado de forma rígida. Cambiar la paleta neutral actualiza la salida de Tailwind automáticamente.
El pipeline de tokens en CI
Los tokens deben construirse y validarse en CI antes de hacer merge. Un archivo de tokens roto debería fallar el build de la misma forma que lo haría un componente roto.
# .github/workflows/tokens.yml
name: Build Design Tokens
on:
pull_request:
paths:
- 'tokens/**'
- 'style-dictionary.config.js'
jobs:
build-tokens:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Instalar dependencias
run: npm ci
- name: Validar esquema de tokens
run: npx ajv validate -s tokens/schema.json -d "tokens/**/*.json"
- name: Construir tokens
run: npx style-dictionary build
- name: Verificar cambios no confirmados
run: |
git diff --exit-code dist/
echo "Las salidas de tokens están actualizadas"# Hook de pre-commit — reconstruir tokens cuando cambia la fuente
#!/bin/sh
# .husky/pre-commit
CHANGED=$(git diff --cached --name-only -- 'tokens/')
if [ -n "$CHANGED" ]; then
npx style-dictionary build
git add dist/
fiEsto garantiza que las salidas de tokens en dist/ siempre coincidan con los archivos fuente. Si un desarrollador cambia un token pero olvida reconstruir, CI lo detecta.
Conclusiones clave
- Los tokens son la única fuente de verdad — un archivo JSON genera CSS, JS, Tailwind y formatos nativos móviles
- Usa tres capas: global, semántica y componente — nunca referencies valores de color crudos en el código de componentes
- El modo oscuro es un intercambio de tokens — los tokens semánticos hacen que los temas sean automáticos sin cambios en componentes
- Style Dictionary maneja la transformación — defínelo una vez, genera para todas partes
- Valida los tokens en CI — los tokens rotos rompen la UI; trátalos como código
- Alimenta la configuración de Tailwind con tokens — estilos basados en clases respaldados por valores del sistema de diseño en lugar de números arbitrarios


