Módulo 2: Design Tokens

Presentación del módulo: design tokens

De las cuatro capas a la primera

En el módulo 1 dibujaste el mapa completo del sistema: las cuatro capastokens → utilidades → componentes → patrones—, cada una apoyada en la de abajo. Viste que el problema que un sistema resuelve es el drift —la divergencia silenciosa de "el mismo" azul escrito a mano en cinco pantallas, que la máquina contó como cuatro valores distintos— y cerraste el módulo haciendo el inventario de Mercado: la lista de piezas que el storefront necesita, capa por capa. Ese inventario es un plano. Todavía no construiste una sola pieza.

Aquí empieza la construcción, y empieza por donde tiene que empezar: los cimientos. Este módulo baja a la capa más baja de las cuatro —los tokens— y la vuelve real. Deja de ser "una decisión nombrada una vez" (el concepto del módulo 1) y pasa a ser algo que defines, escribes y usas: un valor con nombre, en tres niveles, expresado en CSS de verdad, capaz de cambiar un tema entero desde un solo lugar. Al terminar sabrás definir el conjunto de tokens de una app, organizarlos en las tres capas correctas, escribirlos como CSS custom properties y hacer que un mismo token dé un valor en tema claro y otro en tema oscuro sin tocar ni un componente.

No entramos en todo lo que se apoya encima de los tokens todavía. Las escalas concretas —cuántos pasos de espaciado, qué ratios tipográficos— son el módulo 4. Tailwind, la herramienta que consume estos tokens como utilidades, es el módulo 3. Las variantes de componente son el 5. Aquí nos quedamos en la capa 1: qué es un token, en qué tres niveles se organiza, cómo vive en el navegador y cómo cambia con el tema. Es el módulo más "de cimientos" de la guía —todo lo demás referencia lo que definas aquí—.

Conexión con el módulo. Esta es la lección-mapa del módulo 2. No entra a fondo en ninguna pieza: instala la tesis (un token es un valor nombrado por su rol, resuelto por una cadena de tres capas), da el mapa de las ocho lecciones, y ejecuta el primer teaser que conecta el drift del módulo 1 con su cura mecánica. La lección 2 define qué es un token. La 3 presenta las tres capas de tokens —primitivos, semánticos y de componente— y el resolveToken que las recorre. La 4 los baja al navegador con CSS custom properties. La 5 fija la regla dura de nombrarlos por su rol. La 6 los pone a hacer theming claro/oscuro. La 7 arma la paleta completa de Mercado. Y la 8 te pone a definir el set entero tú.

Una analogía: la paleta del pintor

Un pintor que recién empieza mezcla cada color en el momento. Necesita un azul de cielo, así que toma blanco, un poco de azul, una pizca de gris, y mezcla sobre la marcha. Media hora después necesita "el mismo" azul de cielo para otra esquina del cuadro, y vuelve a mezclar —de memoria—. Sale parecido. Pero puestos lado a lado, los dos cielos no son el mismo azul: uno tiene un pelo más de gris, el otro un pelo más de blanco. Es el drift del módulo 1, ahora con pintura: cada mezcla es una decisión ad-hoc, hermosa en aislamiento, divergente en conjunto.

El pintor con oficio hace otra cosa. Antes de empezar, prepara su paleta: mezcla sus colores una vez, los pone en pocillos y los etiqueta por lo que son en el cuadro —"cielo", "sombra", "piel", "acento"—. De ahí en adelante no vuelve a mezclar: moja el pincel en "cielo". Todos los cielos del cuadro salen del mismo pocillo, así que son, físicamente, el mismo azul. Y si a mitad del cuadro decide que el cielo será más cálido, cambia lo que hay en el pocillo "cielo" una vez, y todos los cielos que pinte después salen cálidos —sin repintar los anteriores uno por uno—.

Esa paleta etiquetada son tus tokens. Y fíjate en la distinción que el pintor hace sin pensarlo, porque es el corazón de este módulo:

  • El pocillo con el pigmento —"azul de ftalocianina #2563eb"— es el color crudo. Existe, tiene un valor exacto, pero no dice para qué sirve en este cuadro. Eso es un token primitivo.
  • La etiqueta "cielo" pegada a un pocillo es el color por su papel en la obra. No dice qué pigmento es; dice qué rol cumple. Eso es un token semántico. Y aquí está el truco: la etiqueta "cielo" puede apuntar al pocillo de ftalocianina hoy y a otro más cálido mañana. Cambias a qué pocillo apunta la etiqueta y todos los cielos cambian —la etiqueta es un interruptor—.
  • Y cuando el pintor dice "el acento del marco usa el color de 'sombra'", ató una parte concreta del cuadro a un rol. Eso es un token de componente.

Un pincel que moja en "cielo", que apunta a "azul de ftalocianina", que es #2563eb. Tres eslabones, del papel al pigmento. Esa cadena —de componente a semántico a primitivo a valor— es lo que vas a definir, escribir y ejecutar en este módulo.

Ejemplo trabajado: una decisión, muchos usos

El módulo 1 midió la enfermedad (el drift: cuatro azules donde debía haber uno). Este teaser mide la cura, y es la propiedad que hace de un token un token: está definido en un solo lugar, muchas piezas lo referencian, y cambiarlo una vez actualiza a todas.

Como el navegador no corre en un agente, modelamos la idea con puro JavaScript. Un token —color.primary— vive en un objeto. Tres piezas del storefront (Button, Badge, SearchBar) no copian su valor: lo referencian con una función token(). Luego cambiamos el valor en su único lugar y volvemos a preguntar:

// L1 intro — un token es un valor con nombre; las piezas lo REFERENCIAN, no lo copian.
const tokens = {
  'color.primary': '#2563eb',
  'space-4':       '16px',
  'radius-md':     '8px',
};

function token(name) {
  if (!(name in tokens)) throw new Error('Token desconocido: ' + name);
  return tokens[name];
}

// Tres piezas del storefront que REFERENCIAN el mismo token de color.
const usedBy = ['Button', 'Badge', 'SearchBar'];
console.log('=== color.primary, referenciado por 3 piezas ===');
for (const piece of usedBy) {
  console.log('  ' + piece.padEnd(10) + '-> color.primary = ' + token('color.primary'));
}

// Una sola decision: cambiamos el VALOR del token en un lugar.
tokens['color.primary'] = '#16a34a'; // la marca pasa de azul a verde
console.log('\n=== cambiamos color.primary en UN lugar ===');
for (const piece of usedBy) {
  console.log('  ' + piece.padEnd(10) + '-> color.primary = ' + token('color.primary'));
}

Qué esperar. Al correr el archivo con Node, la salida es exactamente esta:

=== color.primary, referenciado por 3 piezas ===
  Button    -> color.primary = #2563eb
  Badge     -> color.primary = #2563eb
  SearchBar -> color.primary = #2563eb

=== cambiamos color.primary en UN lugar ===
  Button    -> color.primary = #16a34a
  Badge     -> color.primary = #16a34a
  SearchBar -> color.primary = #16a34a

Lee las dos mitades. En la primera, tres piezas distintas del storefront muestran el mismo valor —no porque alguien se acordara de escribir #2563eb tres veces, sino porque las tres apuntan al mismo token—. En la segunda, cambiamos color.primary de azul a verde en una sola línea, y las tres piezas se actualizaron solas. Nadie tocó Button, ni Badge, ni SearchBar. Ese es el superpoder de la capa 1: la marca pasó de azul a verde con una edición, y la onda subió sola por todo lo que referencia el token.

Compara esto con el drift del módulo 1. Allá, "el mismo" azul escrito a mano dio cuatro valores porque cada pantalla lo copiaba. Aquí da un solo valor porque todas lo referencian —y cuando cambia, cambia para todas a la vez—. Copiar crea verdades que divergen; referenciar mantiene una sola. Un token es, mecánicamente, ese acto de referenciar en vez de copiar. Todo el módulo desarrolla esa idea: cómo se define el token, en qué niveles se organiza, cómo se escribe en CSS y cómo un mismo token da distinto valor por tema.

Una pregunta para que la cargues por el resto del módulo: si en vez de color.primary el token se hubiera llamado blue, ¿seguiría teniendo sentido su nombre después de cambiarlo a verde? (Guarda la incomodidad que sentiste al leer blue = #16a34a; la lección 5 la convierte en una regla dura.)

El mapa del módulo

Guarda esta ruta; es cómo cada lección construye la capa de tokens de abajo hacia arriba:

Idea                                       Lección   Concepto clave
─────────────────────────────────────────  ────────  ─────────────────────────────────────
Qué es un token                            L2        un valor con nombre; la UI son
                                                     referencias a tokens, no valores crudos
Primitivos, semánticos y de componente     L3        las 3 capas de tokens y resolveToken:
                                                     button.bg -> color.primary -> blue.600
CSS custom properties                       L4        --color-primary: el token real en el
                                                     navegador (:root y el tema)
Nombrar los tokens por su rol              L5        color.primary, no blue; el nombre debe
                                                     sobrevivir al cambio de valor
Theming claro y oscuro                     L6        cambiar el VALOR del token semántico,
                                                     no el componente
La paleta de Mercado en la práctica         L7        las 3 capas juntas, el set real del
                                                     storefront resuelto en ambos temas
─────────────────────────────────────────  ────────  ─────────────────────────────────────
Proyecto: el set de tokens de Mercado      L8        definir primitivos + semánticos + de
                                                     componente, en CSS, resueltos en 2 temas

La frontera: qué NO entra en este módulo

Saber la frontera te evita mezclar capas que otras lecciones y guías cubren:

  • Las escalas concretas —cuántos pasos de espaciado (base 4/8px), qué ratios de la escala tipográfica, los pasos 50–900 de una paleta— son el módulo 4. Aquí los tokens de espaciado y tipografía aparecen nombrados (space-4, text-lg) como ejemplos de que existen esos roles, pero no construimos la escala que los ordena.
  • Tailwind y el utility-firstp-4, bg-primary, cómo se configura Tailwind para que lea tus tokens— es el módulo 3. Aquí definimos los tokens; allá se consumen como utilidades.
  • Las variantes de componentevariant, size, el patrón cva— son el módulo 5. Aquí un token de componente (button.bg) es un valor atado a una pieza, no un sistema de variantes.
  • El detalle de responsive y dark mode en Tailwind (md:, dark:) es el módulo 6. Aquí hacemos el theming por el valor del token (el mecanismo de fondo); allá se conecta con los prefijos de Tailwind.
  • El contraste accesible —si un par de colores es legible, el algoritmo WCAG— es el módulo 4. Aquí elegimos pares de tokens para claro y oscuro; medir si pasan AA/AAA es allá.

Errores comunes

Creer que "token" es solo otra palabra para "variable de CSS". Qué pasa: alguien oye "design token" y piensa "ah, es --color-primary, una variable, ya lo sé". Por qué pasa: la forma final de un token en el navegador es una CSS custom property, así que parece que ahí se acaba la historia. Cómo detectarlo: defines --blue: #2563eb y --padding: 16px sueltos, sin niveles ni roles, y crees que ya tienes un sistema de tokens. Cómo corregirlo: la variable de CSS es el vehículo, no el concepto. Un token es un valor nombrado por su rol y organizado en tres capas (primitivo, semántico, de componente) que se resuelven en cadena. La lección 3 muestra esas capas y la 4 muestra cómo se vuelven CSS custom properties —el orden importa: primero entiendes las capas, después las escribes—.

Querer definir el color perfecto antes de tener el sistema. Qué pasa: se gastan horas eligiendo el hex exacto del azul de marca antes de haber decidido cómo se organiza la paleta. Por qué pasa: el valor concreto se siente como "lo importante" y la estructura como burocracia. Cómo detectarlo: tienes un #2563eb perfecto pero no sabes si es un primitivo, un semántico, ni cómo lo va a referenciar un botón. Cómo corregirlo: el valor exacto es lo último y lo más fácil de cambiar —lo viste: cambió de azul a verde en una línea—. Lo que da valor al sistema es la estructura: los roles, las capas, la cadena. Define primero los niveles y los nombres; el hex se ajusta al final y las veces que haga falta.

Saltarse el mapa de las capas y "poner tokens donde caigan". Qué pasa: se empieza a crear tokens sin decidir si cada uno es primitivo, semántico o de componente, y terminan mezclados. Por qué pasa: al principio los tres niveles se sienten iguales —todos son "name → value"—. Cómo detectarlo: tienes un token blue.600 junto a button.bg junto a color.primary sin saber cuál puede apuntar a cuál. Cómo corregirlo: hay una dirección obligatoria —de componente a semántico a primitivo a valor—, igual que las cuatro capas del módulo 1 iban de abajo hacia arriba. La lección 3 la fija; llévala como brújula todo el módulo: ¿es un valor crudo? primitivo. ¿es un rol? semántico. ¿está atado a una pieza? de componente.

Ejercicios

Ejercicio 1 — Referencia o copia. Para cada situación, di si describe una referencia a un token (una sola fuente de verdad) o una copia de su valor (una futura fuente de drift):

  • (a) El Button escribe background: #2563eb directamente en su estilo.
  • (b) El Badge usa background: token('color.primary').
  • (c) Tres pantallas escriben cada una padding: 16px a mano en su contenedor.
  • (d) Tres pantallas usan padding: token('space-4').
Ver solución
  • (a) Copia. El valor #2563eb está escrito en el Button. Es una fuente independiente: el día que alguien escriba #3c83f6 en otra pieza, apareció el drift. Nada garantiza que sea el mismo azul que las demás.
  • (b) Referencia. El Badge apunta al token color.primary; no sabe ni le importa qué hex es hoy. Si el token cambia, el Badge cambia con él —sin tocarlo—.
  • (c) Copia (×3). Tres lugares con el mismo 16px escrito a mano son tres verdades que nacen idénticas y divergen con el tiempo. Es la fábrica de drift del módulo 1.
  • (d) Referencia (×3). Las tres apuntan a space-4. Cambiar la escala en un lugar mueve las tres a la vez; siempre serán el mismo espacio porque salen del mismo token.

La regla que se repite todo el módulo: si el valor está escrito en la pieza, es copia y va a divergir; si está nombrado una vez y la pieza lo referencia, es token y se mantiene solo.

Ejercicio 2 — Predice la salida. Sin correr nada, di qué imprimiría la segunda mitad del ejemplo trabajado si, en vez de cambiar color.primary, cambiáramos así:

tokens['color.primary'] = '#7c3aed'; // la marca pasa a morado
Ver solución

Imprimiría las tres piezas con el nuevo valor:

  Button    -> color.primary = #7c3aed
  Badge     -> color.primary = #7c3aed
  SearchBar -> color.primary = #7c3aed

La razón es exactamente la del ejemplo: las tres piezas no guardan un valor, referencian el token. Cualquier valor que le pongas a color.primary —azul, verde, morado— aparece en las tres a la vez, con una sola edición. El valor concreto es lo más fácil de cambiar; la estructura (una fuente, muchas referencias) es lo que no cambia.

Ejercicio 3 — Ubica la pieza en su capa. El módulo 1 te dio las cuatro capas del sistema (tokens → utilidades → componentes → patrones). Para cada afirmación sobre este módulo 2, di si es verdadera o falsa y por qué:

  • (a) "Este módulo construye la capa de componentes."
  • (b) "Un token puede referenciar a otro token."
  • (c) "Tailwind es lo que define los tokens."
Ver solución
  • (a) Falsa. Este módulo construye la capa 1: los tokens —los cimientos—. Los componentes son la capa 3 y su construcción con variantes es el módulo 5. Aquí solo nombramos piezas como Button para mostrar quién referencia los tokens.
  • (b) Verdadera. Es justo el corazón del módulo: un token de componente (button.bg) referencia a un semántico (color.primary), que referencia a un primitivo (blue.600), que es el valor final. Esa cadena de tres niveles es la lección 3.
  • (c) Falsa. Los tokens los defines , en este módulo. Tailwind (módulo 3) es una herramienta que consume tus tokens para generar utilidades; no los define. Se configura con tus tokens, no al revés.

Resumen y siguiente paso

En esta lección instalaste la tesis del módulo 2: un token es un valor nombrado por su rol, definido una vez y referenciado por muchas piezas —la cura mecánica del drift que el módulo 1 diagnosticó—. Con la paleta del pintor viste la distinción que estructura todo lo que viene: el pigmento crudo (primitivo), la etiqueta por su papel en el cuadro (semántico, que funciona como un interruptor), y la parte del cuadro atada a un rol (de componente). Y lo comprobaste ejecutando: color.primary, referenciado por tres piezas, cambió de azul a verde con una edición y actualizó a las tres solas. Copiar divergía; referenciar mantiene una sola verdad.

Antes de avanzar deberías poder: explicar la diferencia entre copiar un valor y referenciar un token; nombrar las tres capas de tokens que verás; y decir por qué el valor concreto es lo más fácil de cambiar y la estructura lo que da el sistema.

La lección 2 baja el primer escalón: qué es exactamente un token. Vas a ver que un token no es solo de color —hay tokens de espaciado, de radio, de sombra, de tipografía— y que el "estilo" de una pieza del storefront no es una lista de valores crudos, sino una lista de referencias a tokens que se resuelven a sus valores. Es la definición formal de la pieza que aquí usaste de forma intuitiva.

Recursos