main content
< Volver a blog sobre aplicaciones móviles

Web components reutilizables y design system en tu aplicación a medida

Cómo implementar web components reutilizables y un design system en tu aplicación a medida

Un botón con un aspecto distinto en cada pantalla. Un formulario que se comporta de una manera en el módulo de clientes y de otra en el de pedidos. Colores que casi coinciden pero no del todo, tipografías que cambian sin motivo aparente, espaciados que parecen elegidos al azar. La aplicación da la sensación de haber sido construida por cinco equipos que nunca se cruzaron en un pasillo. Casi siempre, porque así fue.

Cuando una aplicación web a medida crece sin un design system, la deuda de diseño se acumula despacio, casi en silencio, hasta que un día resulta imposible de gestionar. Cada desarrollador nuevo reinventa los componentes básicos a su manera. Cada funcionalidad introduce pequeñas variaciones que erosionan la experiencia. Cada rebranding se convierte en una excavación arqueológica por el repositorio.

Un design system apoyado en web components reutilizables ataca el problema en su origen. No es un proyecto de diseño disfrazado: es una decisión de ingeniería que repercute en la velocidad de entrega, en la consistencia del producto, en la accesibilidad y en la capacidad de hacer crecer al equipo sin que la coherencia se diluya.

Qué es un design system y qué no es

Un design system no es una guía de estilos. Tampoco es un archivo de Figma con la paleta corporativa, ni una carpeta llamada /components con código suelto que nadie revisa. Es un producto vivo. Incluye principios de diseño escritos, una biblioteca de componentes funcionales con su código fuente, documentación de uso con ejemplos interactivos, tokens de diseño —colores, tipografías, espaciados, sombras— codificados como variables, y procesos claros de contribución y gobernanza.

Funciona como contrato entre diseño y desarrollo. Cuando un diseñador coloca un componente en un mockup, ese componente ya existe en código, está probado, es accesible y se comporta tal como se espera. Cuando un desarrollador necesita un selector de fechas, no lo construye desde cero: usa el de la biblioteca, que ya resuelve la UX, los estados de error, el soporte de teclado y la localización.

Shopify (Polaris), IBM (Carbon), Google (Material) o Atlassian publican sus design systems en abierto. No es altruismo. Un design system bien ejecutado es ventaja competitiva pura: multiplica la productividad de los equipos de producto.

Web components como base tecnológica del design system

La decisión tecnológica más importante al construir un design system se reduce a una pregunta: ¿lo atamos a un framework concreto o lo levantamos sobre estándares web? Aquí los web components ofrecen una ventaja difícil de ignorar. Funcionan en cualquier contexto.

Un web component construido con Custom Elements y Shadow DOM funciona en React, en Angular, en Vue, en Svelte, en una página HTML estática y, con bastante probabilidad, en el framework que aparezca dentro de cinco años. Esa independencia importa especialmente en aplicaciones a medida donde conviven módulos con tecnologías distintas, o donde una migración se ve venir en el horizonte.

Custom Elements: la base

Un Custom Element es una clase JavaScript que extiende HTMLElement y se registra con un nombre de etiqueta personalizado. Una vez registrado, se usa en el HTML como cualquier elemento nativo.

class TgButton extends HTMLElement {
  static get observedAttributes() {
    return ['variant', 'size', 'disabled'];
  }

  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
  }

  connectedCallback() {
    this.render();
  }

  attributeChangedCallback() {
    this.render();
  }

  render() {
    const variant = this.getAttribute('variant') || 'primary';
    const size = this.getAttribute('size') || 'medium';
    this.shadowRoot.innerHTML = `
      <style>
        :host { display: inline-block; }
        button {
          font-family: var(--tg-font-family, sans-serif);
          border-radius: var(--tg-border-radius, 4px);
          cursor: pointer;
          /* estilos según variant y size */
        }
      </style>
      <button part="button">
        <slot></slot>
      </button>
    `;
  }
}

customElements.define('tg-button', TgButton);

Shadow DOM: encapsulación real

El Shadow DOM crea un árbol DOM aislado dentro del componente. Los estilos que viven dentro no escapan al exterior, y los del exterior no se cuelan hacia dentro, salvo por puertas controladas como las CSS Custom Properties y los CSS Parts. Esa encapsulación elimina uno de los dolores recurrentes en aplicaciones grandes: la guerra silenciosa de CSS entre componentes.

Lit: web components sin boilerplate

Escribir web components con la API nativa pesa. Es verboso. Lit, mantenido por el equipo de Google, recorta drásticamente ese boilerplate sin renunciar a la compatibilidad con el estándar. Un componente Lit ocupa menos de 5 KB comprimido —biblioteca incluida— y ofrece renderizado declarativo, propiedades reactivas y una gestión del DOM razonablemente eficiente.

import { LitElement, html, css } from 'lit';

class TgCard extends LitElement {
  static properties = {
    heading: { type: String },
    elevated: { type: Boolean }
  };

  static styles = css`
    :host {
      display: block;
      border: 1px solid var(--tg-color-border, #e0e0e0);
      border-radius: var(--tg-border-radius-lg, 8px);
      padding: var(--tg-spacing-md, 16px);
    }
    :host([elevated]) {
      box-shadow: var(--tg-shadow-md, 0 4px 12px rgba(0,0,0,0.1));
    }
    h2 { margin-top: 0; }
  `;

  render() {
    return html`
      <h2>${this.heading}</h2>
      <slot></slot>
    `;
  }
}

customElements.define('tg-card', TgCard);

Lit no es la única vía. Stencil, de Ionic, genera web components a partir de una sintaxis cercana a React con JSX y TypeScript. FAST Element, de Microsoft, apuesta más por el rendimiento. La elección depende del gusto y la experiencia del equipo, pero todas escupen web components estándar y compatibles entre sí.

Atomic design: organizando componentes de menor a mayor

La metodología atomic design, propuesta por Brad Frost, da un marco mental para ordenar los componentes de un design system en cinco niveles de abstracción. Es una taxonomía, no una religión.

Átomos

Los elementos más básicos. Indivisibles. Un botón, un input de texto, una etiqueta, un icono, un avatar. Sin lógica de negocio ni dependencias de otros componentes. Son los ladrillos del sistema.

Moléculas

Combinaciones simples de átomos que funcionan como una unidad. Un campo de formulario —label más input más mensaje de error— es una molécula. Una barra de búsqueda —input más botón más icono de lupa— también. Empiezan a tener comportamiento propio, pero todavía se mantienen genéricas.

Organismos

Grupos de moléculas y átomos que forman secciones funcionales de la interfaz. Un encabezado de página con logo, navegación y menú de usuario es un organismo. Un formulario de registro completo, otro. Aquí asoma el contexto de negocio.

Templates

Estructuras de página que indican dónde van los organismos, pero sin datos reales. El esqueleto de una vista, la composición que define el layout antes de poner el contenido encima.

Páginas

Templates con datos reales. La instancia final que ve el usuario. Estrictamente, no forman parte del design system: son el resultado de combinar sus piezas con los datos concretos de la aplicación.

En la práctica, los design systems que sobreviven suelen simplificar esta taxonomía a tres niveles: componentes básicos —átomos y moléculas—, componentes compuestos —organismos— y patterns o layouts. Lo importante no es la etiqueta, sino que todo el equipo comparta la misma jerarquía mental.

Design tokens: el lenguaje compartido entre diseño y código

Los design tokens son las decisiones de diseño codificadas como variables. Colores, tipografías, espaciados, sombras, bordes, tiempos de animación, breakpoints. La fuente única de verdad que garantiza que "azul primario" signifique exactamente el mismo color en Figma, en el CSS del design system, en la app móvil y en los emails transaccionales.

Una estructura de tokens bien planteada tiene al menos dos capas. Los tokens globales o primitivos contienen los valores base: color-blue-500: #2563EB, spacing-4: 16px, font-size-lg: 18px. Los tokens semánticos les dan significado en contexto: color-primary: color-blue-500, spacing-component-padding: spacing-4, font-size-heading: font-size-lg.

Esa separación es lo que permite cambiar el tema visual de la aplicación entera tocando solo los tokens semánticos. Si la marca decide mañana virar su azul, modificas un token y el cambio se propaga por sí solo a cada componente.

Herramientas como Style Dictionary, de Amazon, o Theo, de Salesforce, dejan definir los tokens en un formato neutral —JSON o YAML— y generar las salidas específicas de cada plataforma: CSS Custom Properties para la web, XML para Android, Swift para iOS.

Storybook: documentación viva y entorno de desarrollo

Storybook se ha convertido en el estándar de facto para desarrollar, documentar y probar componentes de UI de forma aislada. Funciona como un catálogo interactivo donde cada componente expone sus "stories": los estados y configuraciones que cubren todas sus variantes.

Por qué Storybook es imprescindible

Desarrollo aislado: los desarrolladores trabajan en un componente sin necesidad de levantar la aplicación entera. Acelera el ciclo y permite detectar problemas pronto, cuando todavía son baratos.

Documentación viva: las stories no envejecen mal porque son el propio componente ejecutándose. Si el componente cambia, la story lo refleja sin intervención humana.

Testing visual: herramientas como Chromatic, del propio equipo de Storybook, permiten testing de regresión visual automatizado y atrapan cambios inesperados en la apariencia de los componentes antes de que lleguen a producción.

Colaboración: diseñadores, product managers y QA pueden revisar los componentes en Storybook sin levantar un entorno de desarrollo. La distancia entre disciplinas se acorta y los malentendidos clásicos entre diseño y desarrollo se vuelven menos frecuentes.

Storybook con web components

Storybook soporta web components de forma nativa mediante @storybook/web-components. Las stories se escriben con lit-html para renderizar los componentes.

export default {
  title: 'Components/Button',
  component: 'tg-button',
  argTypes: {
    variant: {
      control: { type: 'select' },
      options: ['primary', 'secondary', 'ghost']
    },
    size: {
      control: { type: 'select' },
      options: ['small', 'medium', 'large']
    }
  }
};

export const Primary = {
  args: {
    variant: 'primary',
    size: 'medium',
    slot: 'Guardar cambios'
  }
};

Accesibilidad: no es opcional, es fundamental

Un design system que no incorpora accesibilidad desde el primer trazo está incompleto. No es una capa que se añade al final, ni un checklist que se revisa el día antes del lanzamiento. Es una propiedad intrínseca de cada componente, igual que su tipografía o su radio de borde.

Requisitos mínimos para cada componente

Cada componente del design system debería cumplir, como suelo, el nivel AA de las WCAG (Web Content Accessibility Guidelines). En la práctica, eso se traduce en varios frentes.

Navegación por teclado: todos los elementos interactivos deben ser operables sin ratón. Un dropdown abre con Enter, navega con flechas y cierra con Escape. Un dialog atrapa el foco mientras está abierto y se lo devuelve al elemento que lo invocó al cerrarse.

Roles ARIA: los web components deben exponer los roles y atributos ARIA que correspondan. Un componente de tabs necesita role="tablist", role="tab" y role="tabpanel". Una notificación o toast requiere role="alert" o aria-live="polite".

Contraste de color: los tokens de color deben garantizar ratios mínimos de 4.5:1 para texto normal y 3:1 para texto grande, según WCAG AA. La exigencia repercute directamente en cómo definimos los design tokens.

Textos alternativos y etiquetas: cada elemento visual relevante debe llevar su alternativa textual accesible para lectores de pantalla.

Shadow DOM y accesibilidad

El Shadow DOM trae sus propios retos. Los elementos dentro de un Shadow DOM quedan fuera del alcance de los selectores CSS externos, lo que complica algunas hojas de alto contraste. Los formularios merecen atención específica: los controles que viven dentro de un Shadow DOM no participan automáticamente en el formulario padre, y la asociación correcta requiere el API de ElementInternals.

Si tu equipo necesita orientación para diseñar un design system que se adapte a la realidad de tu producto y tus equipos, o para implementar una biblioteca de componentes reutilizables que acelere tu desarrollo, podemos ayudarte a definir la estrategia y la ejecución técnica.

Theming: más allá del modo oscuro

Un sistema de theming sólido permite que la misma biblioteca se adapte a contextos visuales distintos sin tocar el código de los componentes. Los casos habituales: modo claro y oscuro, marca blanca para diferentes clientes, ajustes de alto contraste por accesibilidad y variaciones regionales.

Las CSS Custom Properties —las variables CSS de toda la vida, pero con superpoderes— son el mecanismo nativo del navegador para implementar theming. Si todas las decisiones visuales viven como custom properties, cambiar de tema se reduce a actualizar sus valores en un selector raíz.

/* Tema claro (por defecto) */
:root {
  --tg-color-bg: #ffffff;
  --tg-color-text: #1a1a1a;
  --tg-color-primary: #2563EB;
  --tg-color-surface: #f5f5f5;
}

/* Tema oscuro */
:root[data-theme="dark"] {
  --tg-color-bg: #121212;
  --tg-color-text: #e0e0e0;
  --tg-color-primary: #60a5fa;
  --tg-color-surface: #1e1e1e;
}

Los web components con Shadow DOM consumen estas custom properties por herencia CSS. Las custom properties son una de las pocas cosas que atraviesan la barrera del Shadow DOM, lo que las convierte en el mecanismo natural para llevar las decisiones de theming al interior de cada componente.

Consistencia entre equipos: gobernanza y procesos

Un design system sin gobernanza es una biblioteca de componentes que nadie usa. La adopción no llega por decreto. Llega cuando usar el design system es más fácil que no usarlo.

Modelo de contribución

Define con claridad cómo se proponen nuevos componentes, cómo se revisan y cómo se incorporan al sistema. Un proceso típico empieza con una propuesta con caso de uso documentado, sigue con una revisión del equipo de design system —diseño y desarrollo en la misma mesa—, continúa con la implementación acompañada de tests y documentación, pasa por una revisión específica de accesibilidad y termina con la aprobación final.

Versionado y distribución

El design system debe publicarse como un paquete npm —o su equivalente en tu ecosistema— con versionado semántico. Los cambios que rompen compatibilidad hacia atrás se comunican con antelación y documentan la ruta de migración. Un CHANGELOG claro y detallado no es un lujo: es lo que separa una biblioteca seria de un experimento.

Métricas de adopción

Mide la adopción real. Qué porcentaje de componentes en producción provienen del sistema. Cuántos componentes custom siguen viviendo fuera del sistema. Con qué frecuencia se reportan bugs en los componentes oficiales frente a los ad-hoc. Estas métricas justifican la inversión continua en el design system y revelan los huecos donde el sistema no está cubriendo necesidades reales de los equipos.

Errores comunes al construir un design system

Empezar demasiado grande: pretender catalogar todos los componentes posibles antes de tener nada en producción. Preferible empezar con diez componentes básicos bien hechos y crecer al ritmo de la demanda real.

Ignorar el feedback de los consumidores: si los equipos que usan el design system avisan de que un componente cuesta de usar o no cubre sus casos, y esos avisos se ignoran, dejarán de usarlo. La API de cada componente se diseña pensando en quien la consume, no en quien la implementa.

No invertir en documentación: un componente sin documentación es, a efectos prácticos, un componente que no existe. Cada uno necesita ejemplos de uso, descripción de propiedades, variantes disponibles, criterios de cuándo usarlo y cuándo no, y consideraciones de accesibilidad.

Acoplar el design system a un framework: si el sistema solo funciona con React 18 y otro módulo necesita migrar a la siguiente versión mayor, tienes un problema con fecha de caducidad. Los web components eliminan ese riesgo por construcción.

Conclusión: el design system como multiplicador de velocidad

Un design system no es un proyecto que se termina. Es un producto que se mantiene, evoluciona y crece con la aplicación. La inversión inicial pesa, sí, pero el retorno se nota en cada funcionalidad que se construye más rápido porque los componentes ya están, en cada bug de UI que no llega a ocurrir porque el componente está probado, en cada desarrollador nuevo que se vuelve productivo en días en vez de en semanas.

Construir sobre web components estándar protege esa inversión a largo plazo. Los frameworks van y vienen. Los estándares web se quedan. Un design system asentado sobre Custom Elements, Shadow DOM y CSS Custom Properties funcionará hoy con tu stack actual y seguirá funcionando cuando ese stack cambie. Que cambiará.

Contacta con nosotros
Fila 1