Volver al Blog
UX/UI Design28 de noviembre de 202510 min de lectura

Construyendo un Design System desde cero: Por dónde empezar realmente

DR

Doug Ribeiro

10 min de lectura

En Wonderlabs construí la librería de componentes reutilizables del equipo y la base de design system debajo de ella, para una PWA de tarjeta de crédito que servía a más de 50.000 usuarios, con un equipo de front-end de tres personas. Caímos en la trampa que atrapa a la mayoría de los equipos. Empezamos con componentes. Se siente productivo. Estás diseñando botones, cards, modals, y entregando artefactos. Pero sin tokens debajo, esos componentes están construidos sobre arena.

Por qué empezar con componentes te cuesta después

En Wonderlabs, diseñamos componentes durante meses antes de formalizar tokens. Cuando nos alineamos en la estructura de tokens, tuvimos que auditar cada componente y reemplazar valores hardcodeados. Se comió más de un sprint e introdujo regresiones. No es un riesgo hipotético. Es lo que pasa.

El problema es que cuando diseñas un botón antes de definir tus tokens de color, estás tomando decisiones que parecen decisiones de diseño pero en realidad son decisiones de datos. Eliges un azul para la acción primaria. ¿Cuál azul? ¿Cómo se relaciona con el color de marca? ¿De qué se deriva el estado hover? ¿Qué cambia en dark mode? Sin tokens, esos son valores arbitrarios integrados en el componente. Cuando la marca se refresca o un segundo producto necesita el sistema, no estás actualizando un token. Estás buscando en cada componente valores hardcodeados.

El orden correcto

  • 1. Design tokens: escalas de color raw, escalas de tipografía, escala de espaciado, border radii, elevación, motion. Estos son tus valores primitivos.
  • 2. Tokens semánticos: mapean tokens raw a intención. --color-brand-blue-500 se convierte en --color-action-default. Esta capa maneja theming y dark mode.
  • 3. Primitivas: estilos base de Figma y CSS custom properties de Angular derivados de tokens semánticos. Ningún componente todavía.
  • 4. Componentes base: Button, Input, Badge, Tag. Cada uno referencia solo tokens. Sin valores hardcodeados.
  • 5. Componentes compuestos: DataTable, FormGroup, NavigationBar construidos a partir de componentes base.
  • 6. Templates de página: patrones de layout usados en todo el producto.

Arquitectura de tokens: JSON como única fuente de verdad

La decisión técnica más importante en un design system es mantener los tokens de Figma y los tokens de código sincronizados. El enfoque que funciona es un archivo JSON de tokens, versionado en el repositorio, que el código trata como la única fuente de verdad. Un paso de build como Style Dictionary transforma ese JSON en CSS custom properties para Angular, constantes Swift para iOS, o lo que la plataforma necesite. Cómo llega ese JSON ahí es una decisión con dos respuestas. Escribirlo en código y sincronizarlo hacia Figma con un plugin como Tokens Studio, o escribirlo en Figma Variables y exportarlo. Elige una dirección y déjala por escrito, porque un equipo que nunca elige termina con dos fuentes que se separaron y sin forma de decir cuál es la correcta. En Wonderlabs tomé el segundo camino, en mis últimos meses ahí en 2023, una vez que Figma Variables existía: tokens definidos en Figma Variables, exportados como JSON, transformados con Style Dictionary en CSS custom properties consumidas por nuestros componentes Angular, que se apoyaban en Angular Material. Storybook entró solo un poco, cerca del final.

Decide el formato del archivo de tokens antes de escribir el primer token, porque las dos formas que circulan no se mezclan dentro de un mismo archivo. El ejemplo de abajo es Style Dictionary v3, donde cada token es un objeto con una clave value. Style Dictionary v4 y el DTCG Design Tokens Format Module usan $value y $type en su lugar. Usé v3 en Wonderlabs y el snippet lo refleja. En un proyecto nuevo hoy escribiría la forma DTCG, porque hacia ahí va el tooling, y después verificaría que cada plugin y cada paso de build de la cadena realmente la lee.

json
{
  "color": {
    "brand": {
      "blue": {
        "50":  { "value": "#EFF6FF" },
        "100": { "value": "#DBEAFE" },
        "500": { "value": "#3B82F6" },
        "700": { "value": "#1D4ED8" },
        "900": { "value": "#1E3A8A" }
      }
    },
    "action": {
      "default":  { "value": "{color.brand.blue.500}" },
      "hover":    { "value": "{color.brand.blue.700}" },
      "disabled": { "value": "{color.brand.blue.100}" }
    }
  },
  "spacing": {
    "xs":  { "value": "4px" },
    "sm":  { "value": "8px" },
    "md":  { "value": "16px" },
    "lg":  { "value": "24px" },
    "xl":  { "value": "32px" },
    "2xl": { "value": "48px" }
  }
}
Figma Variables tokens.json Style Dictionary Variables CSS / SCSS Componentes

La gobernanza es parte del sistema, no un problema posterior

Un design system sin un proceso de contribución se convierte en un depósito de basura en cuestión de meses. Define temprano quién puede agregar tokens, quién puede agregar componentes, y cuál es el proceso de revisión. Incluso en un equipo de front-end de tres personas esto no es opcional. Un componente que se lanza con un patrón de accesibilidad roto se usa en muchas features antes de que el bug aparezca. Un workflow basado en PR con un diseñador y un desarrollador como revisores requeridos detecta la mayoría de los problemas antes de que se propaguen.

El versionado importa más de lo que la mayoría de los equipos esperan cuando empiezan. Cuando cambias una API de componente o renombras un token, los equipos que consumen necesitan tiempo para migrar. Nunca nos topamos con eso en Wonderlabs. Tres personas, un producto, y la librería se entregaba dentro de la app, así que había exactamente un consumidor y un renombrado era un solo commit. El día que un segundo producto toma la librería, eso deja de funcionar. Esa es la parte que armaría desde el principio la próxima vez: la librería publicada como un paquete npm scoped, versionado semántico en cada release, y schematics de Angular para las migraciones que rompen. Sin eso, los equipos se quedan en versiones antiguas indefinidamente y terminas manteniendo dos versiones del sistema.

Un design system es un producto, no un proyecto. Necesita mantenimiento, versionado, documentación, y un equipo que lo posea. Trátalo como una construcción de una sola vez y se pudrirá en un año.

Integración con Angular: CSS Custom Properties y overrides de tema

La forma que le daría la próxima vez, para Angular: el design system publicado como un paquete npm scoped y consumido a través de librerías Angular en un monorepo. Los componentes exponen sus estilos a través de CSS custom properties mapeadas desde el archivo de tokens. Las apps que consumen tematizan sobreescribiendo esas custom properties a nivel de host, nunca modificando código de componentes. Esa es la arquitectura que hace viable el multi-marca. Una segunda marca se vuelve un segundo conjunto de valores de tokens aplicado en el host, no un fork del código de los componentes.

Si empezara ese sistema de nuevo, los tokens serían el primer entregable. Antes de que exista un solo componente en Figma, la escala de colores, el mapeo de tokens semánticos, y la escala de espaciado van a un archivo de tokens revisado. Cada decisión de componente tomada después tiene una base para referencia. El retrabajo que evitas vale mucho más que el tiempo extra dedicado a tokens al principio.

Referencias

Design SystemsFigmaUX DesignAngular