
Cómo crear un sistema de diseño con Storybook y Tailwind (React) - Guía Paso a Paso

¿Alguna vez te has sentido abrumado tratando de mantener la consistencia en la interfaz de tus aplicaciones React? ¡No estás solo!
En esta guía práctica, te acompañaré en la creación de un potente sistema de diseño utilizando Storybook y Tailwind CSS en React. Ya seas que estes desarrollando de manera individual o formes parte de un equipo, aprenderás a construir componentes de UI mantenibles y escalables que harán que tu proceso de desarrollo sea pan comido. 🚀
¿Qué es un Sistema de Diseño? 🤔
Un sistema de diseño es tu arma secreta para construir interfaces de usuario consistentes y mantenibles a escala. Piensa en él como el ADN 🧬 de tu proyecto: una colección de componentes y guias de estilo reutilizables que trabajan juntos de forma armoniosa.
Por Qué Lo Necesitas 🎯
- Consistencia: Asegura que tu UI mantenga el mismo lenguaje visual en toda tu aplicación.
- Eficiencia: Construye nuevas funcionalidades más rápido reutilizando componentes existentes.
- Mantenibilidad: Realiza cambios en un solo lugar y velos reflejados en todas partes.
- Colaboración: Proporciona una fuente única de verdad para diseñadores y desarrolladores.
En esta guía, te mostraré cómo aprovechar el poder de Storybook y Tailwind CSS para crear un sistema de diseño robusto en React que a tu equipo le encantará usar.
¿Por Qué Storybook + Tailwind = La Combinación Perfecta? 💪
Hablemos de por qué este dúo dinámico es la elección perfecta para tu sistema de diseño:
Storybook 📚
- Construye y prueba componentes de forma aislada.
- Documentación interactiva que se mantiene actualizada.
- Pruebas visuales y depuración simplificadas.
- Perfecto para el desarrollo basado en componentes (component-driven development).
Tailwind CSS 🎨
- Enfoque “utility-first” para un estilizado rápido.
- Tokens de diseño consistentes de fábrica.
- Altamente personalizable para que coincida con tu marca.
- CSS de “zero-runtime” para un rendimiento óptimo.
¡Juntos, crean un flujo de trabajo potente que hace que construir y mantener sistemas de diseño sea muy sencillo! 🚀
Vamos a configurar nuestro proyecto
Para empezar, necesitamos crear un nuevo proyecto. En este caso, vamos a usar Vite. Asumiré que tienes Node.js instalado en tu máquina y que ya sabes cómo crear un proyecto de React. Si no, puedes seguir la documentación oficial aquí.
Puedes crear un nuevo proyecto (React) usando el siguiente comando:
pnpm create vite my-design-system --template react-ts
Estoy usando pnpm
como mi gestor de paquetes, pero puedes usar npm
, yarn
o bun
si lo prefieres. También es importante mencionar que estoy usando TypeScript. Esto nos ayudará a tener una mejor experiencia de desarrollo, ya que tener nuestros componentes tipados nos proporcionará autocompletado y verificación de tipos para nuestros componentes.
Ahora que tenemos nuestro proyecto creado, instalemos Storybook y Tailwind CSS.
Configurando Tailwind CSS 🎨
Primero, agreguemos el poder de Tailwind CSS a nuestro proyecto. Esta será la base del estilizado de nuestro sistema de diseño. Puedes hacerlo siguiendo la documentación oficial aquí, o puedes seguir los pasos a continuación:
pnpm install tailwindcss @tailwindcss/vite
🔧 ¡Hora de configurar! Vamos a configurar Tailwind:
- Primero, crea un archivo
tailwind.config.ts
:
pnpm dlx tailwindcss init -p
- Actualiza tu
vite.config.ts
para integrar Tailwind:
import { defineConfig } from 'vite';
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
plugins: [tailwindcss(), react()],
});
Y finalmente, en tu archivo CSS principal (generalmente src/index.css
), necesitas importar Tailwind CSS:
@import 'tailwindcss';
Instalando y Configurando Storybook 📚
Ahora que tenemos Tailwind funcionando, agreguemos Storybook a nuestra caja de herramientas. Storybook será nuestro “parque de juegos” y centro de documentación de componentes. Puedes instalarlo siguiendo la documentación oficial aquí, o puedes seguir los pasos a continuación:
Ejecuta el siguiente comando:
pnpm create storybook@latest
🎯 Guía Rápida de Configuración Durante la instalación, verás varias opciones. Para este tutorial:
- ✅ Documentation (Requerido)
- ❌ Desmarca otras opciones (Podemos agregarlas después si es necesario)
El instalador:
1. Agregará las dependencias de Storybook. 2. Creará historias de ejemplo iniciales. 3. Configurará archivos de configuración. 4. Agregará scripts npm a tu package.json
.
Una vez instalado, puedes iniciar el servidor de desarrollo de Storybook:
pnpm storybook
Tu “parque de juegos” de componentes estará disponible en http://localhost:6006
🚀
Creando la Base de Nuestro Sistema de Diseño 🎨
Definiendo Colores y Tokens Personalizados
Antes de sumergirnos en los componentes, establezcamos la base de nuestro sistema de diseño: los tokens de diseño. Estos son los bloques de construcción básicos que asegurarán la consistencia en toda tu aplicación.
🎨 ¿Qué son los Tokens de Diseño? Los tokens de diseño son las unidades más pequeñas de tu sistema de diseño. Representan:
- Colores
- Tipografía
- Espaciado
- Sombras
- Tiempos de animación
- ¡Y más!
Configurando los Tokens de Diseño
Quiero que este sistema de diseño sea modular y fácil de mantener, así que voy a crear un nuevo archivo CSS para nuestros colores y tokens personalizados. Puedes omitir este paso si quieres, pero creo que es un mejor enfoque tener esto separado del archivo CSS principal.
Crea una nueva carpeta llamada
css
dentro de la carpetasrc
, y luego crea un nuevo archivo llamadodesign-tokens.css
dentro de la carpetacss
.Para esta guía, nos centraremos en una paleta de colores simple pero efectiva:
- 🟢 Primario: Verde salvia suave
- 🔵 Secundario: Azul verdoso intenso
- 🟡 Acento: Naranja vibrante
- ⚪ Fondo: Blanco cálido
El contenido de nuestro archivo design-tokens.css
será:
@theme {
--color-primary: #c1d8c3;
--color-secondary: #6a9c89;
--color-accent: #ffa725;
--color-background: #fff5e4;
}
Configuramos nuestros tokens de diseño en Tailwind
Ahora que hemos definido nuestros tokens de diseño, necesitamos incluirlos en nuestro archivo CSS principal para poder usarlos en nuestros componentes. Podemos hacer esto agregando el siguiente código a nuestro archivo index.css
:
@import 'tailwindcss';
@import './css/design-tokens.css';
Eso es todo. Ahora tenemos nuestros colores y tokens personalizados definidos en nuestra configuración de Tailwind. Podemos usarlos en nuestros componentes, lo que nos ayudará a tener colores consistentes en toda nuestra aplicación.
Organizando nuestro Sistema de Diseño
Ya tenemos nuestro proyecto listo para empezar a trabajar en nuestro sistema de diseño, pero antes de empezar a crear componentes, crearemos una estructura de carpetas para organizar nuestro sistema de diseño. Esto nos ayudará a tener una mejor comprensión de nuestros componentes y facilitará su mantenimiento.
🧬 Estructura de Atomic Design
La estructura de carpetas se basará en los principios de “Atomic Design”. Si no estás familiarizado con este concepto, te recomiendo encarecidamente que leas el libro Atomic Design, de Brad Frost. Es un libro excelente que explica el concepto de “Atomic Design” y cómo aplicarlo en tus proyectos.
🌳 Estructura del Proyecto:
src/
├── components/
│ └── design-system/
│ ├── atoms/ # Bloques de construcción básicos (botones, inputs, textos)
│ ├── molecules/ # Composiciones de componentes simples
│ └── organisms/ # Composiciones de componentes complejas
- Átomos (
atoms/
)
- Bloques de construcción fundamentales. - No se pueden descomponer más. - Ejemplos: botones, inputs, labels, encabezados. - Deben ser altamente reutilizables e independientes del contexto.
- Moléculas (
molecules/
)
- Combinaciones simples de átomos. - Tienen una única responsabilidad. - Ejemplos: barras de búsqueda (input + botón), campos de formulario (label + input). - Deben centrarse en una tarea de interfaz específica.
- Organismos (
organisms/
) - Secciones de UI complejas. - Compuestos por átomos y moléculas. - Pueden ser sensibles al contexto. - Ejemplos: barras de navegación, secciones de pie de página, formularios. - Representan secciones distintas de una interfaz.
Esta estructura ayuda a mantener una clara separación de responsabilidades y facilita la gestión de la complejidad de los componentes a medida que tu sistema de diseño crece.
Construyendo Nuestro Primer Componente 🏗️
¡Manos a la obra! Vamos a crear nuestro primer componente: un componente “Heading” que demostrará conceptos clave del desarrollo de componentes con Storybook y Tailwind.
Configurando Funciones de Utilidad 🛠️
Antes de sumergirnos en la creación de componentes, configuremos algunas utilidades esenciales que nos harán la vida más fácil:
Primero, crea un directorio de utilidades. Dentro de la carpeta
src
, crea una nueva carpeta llamadalib
, y dentro de esta nueva carpeta crea un archivo llamadoutils.ts
.Instala las dependencias requeridas:
pnpm add clsx tailwind-merge class-variance-authority
💡 ¿Por qué estos paquetes?
- clsx: Utilidad para construir cadenas de
className
.- tailwind-merge: Una forma inteligente de fusionar clases de Tailwind sin conflictos.
- class-variance-authority: Gestión de variantes de componentes con tipado seguro (type-safe).
- Crea nuestra utilidad para fusionar clases en
src/lib/utils.ts
:
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
};
Requisitos del Componente 📋
Creemos un componente de encabezado que muestre las mejores prácticas para nuestro sistema de diseño. Nuestro componente tendra:
✨ Características:
- Múltiples variantes (default, accent)
- Niveles de encabezado semánticos (h1-h6)
- Props con tipado seguro
- Personalizable a través de
className
🎯 Requisitos Técnicos:
interface HeadingProps {
variant?: 'default' | 'accent';
level: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
className?: string;
children: React.ReactNode;
}
Creando el componente
Dentro de la carpeta atoms
, crea una nueva carpeta llamada heading/
, y dentro de esta carpeta crea un nuevo archivo llamado heading.tsx
y un archivo llamado heading.stories.ts
.
Primero, en nuestro archivo heading.tsx
, vamos a definir nuestro componente de encabezado. El contenido de este archivo será:
import { cn } from '@/lib/utils';
export default function Heading({ className, level, variant = 'default', children }: HeadingProps) {
const Heading = level;
return (
<Heading
className={cn(
'font-normal',
variant == 'accent' && 'text-accent',
variant == 'default' && 'text-secondary',
className
)}
>
{children} {' '}
</Heading>
);
}
export type HeadingProps = {
children: React.ReactNode;
level: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
className?: string;
variant?: 'default' | 'accent';
};
export { Heading };
Como puedes ver en nuestro nuevo archivo, creamos un componente de encabezado básico que soporta diferentes variantes, niveles de encabezado y clases personalizadas. Estamos utilizando nuestros tokens de diseño previamente definidos en nuestro archivo CSS con Tailwind, y ahora podemos usar este componente en toda nuestra aplicación.
Una implementación de este componente se vería algo así:
<Heading level="h2">¡Ahora nuestro componente está funcionando! 🙌</Heading>
Subiendo de Nivel: Agregando Variantes con Tipado Seguro 🚀
Nuestro componente de encabezado funciona, pero hagámoslo más robusto y mantenible usando class-variance-authority (CVA). Esta potente herramienta nos ayudará a:
✨ Beneficios de Usar CVA:
- Variantes y combinaciones con tipado seguro.
- Soporte de autocompletado en tu IDE.
- Código más limpio y mantenible.
- Fácil de escalar con nuevas variantes.
Refactorizando Nuestro Componente
Vamos a transformar nuestro componente de encabezado en una versión más potente y flexible. Agregaremos:
- Múltiples opciones de tamaño.
- Controles de alineación de texto.
- Valores predeterminados (fallbacks).
Aquí está nuestro heading.tsx
mejorado:
import { cn } from '@/lib/utils';
import { cva, type VariantProps } from 'class-variance-authority';
export default function Heading({
className,
level,
variant = 'default',
size = 'base',
align = 'left',
children,
}: HeadingProps) {
const Heading = level;
return (
<Heading className={cn(headingVariants({ variant, size, align }), className, 'font-normal')}>
{children} {' '}
</Heading>
);
}
const baseClasses = 'font-normal';
const headingVariants = cva(baseClasses, {
variants: {
variant: {
default: 'text-secondary',
accent: 'text-accent',
},
size: {
sm: 'text-sm',
base: 'text-base',
lg: 'text-lg',
xl: 'text-xl',
'2xl': 'text-2xl',
'3xl': 'text-3xl',
'4xl': 'text-4xl',
},
align: {
left: 'text-left',
center: 'text-center',
right: 'text-right',
},
},
defaultVariants: {
size: 'base',
align: 'left',
variant: 'default',
},
});
export type HeadingProps = {
children: React.ReactNode;
level: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
className?: string;
} & VariantProps<typeof headingVariants>;
export { Heading };
🔍 Análisis del Código:
1. Estilos Base: Definimos estilos comunes que se aplican a todos los encabezados. 2. Variantes: Cada grupo de variantes (variant
, size
, align
) representa un aspecto diferente de personalización. 3. Tipado Seguro: Soporte completo de TypeScript con tipos exportados. 4. Extensibilidad: Soporte de className
personalizado para personalización adicional.
Ejemplos de Uso 🎯
// Uso básico
<Heading level="h1">Bienvenido a nuestra aplicación</Heading>
// Con variantes
<Heading
level="h2"
variant="accent"
size="2xl"
align="center"
>
Productos Destacados
</Heading>
Creando Documentación con Storybook 📚
Creemos la documentación de Storybook para nuestro componente de encabezado. Podemos declarar estos archivos donde queramos, siempre y cuando sigamos el patrón *.stories.ts
. Storybook detectará automáticamente este archivo como una historia de Storybook (a mí me gusta mantener la documentación de historias dentro de una carpeta con su archivo de componente correspondiente para que sea fácil de mantener e identificar).
Nuestro archivo es heading.stories.tsx
:
import type { Meta, StoryObj } from '@storybook/react';
import { Heading } from './heading';
const meta = {
title: 'Design System/Atoms/Heading',
component: Heading,
argTypes: {
level: {
control: 'select',
options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
},
size: {
control: 'select',
options: ['sm', 'base', 'lg', 'xl', '2xl', '3xl', '4xl'],
},
align: {
control: 'select',
options: ['left', 'center', 'right'],
},
variant: {
control: 'select',
options: ['default', 'accent'],
},
},
args: {
level: 'h1',
children: 'Heading',
variant: 'default',
align: 'left',
size: 'base',
},
} satisfies Meta<typeof Heading>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Playground: Story = {};
export const Default: Story = {
args: {
level: 'h1',
children: 'Default Heading',
variant: 'default',
align: 'left',
size: 'base',
},
argTypes: {
variant: {
table: {
disable: true,
},
},
},
};
export const Accent: Story = {
args: {
level: 'h1',
children: 'Accent Heading',
variant: 'accent',
align: 'left',
size: 'base',
},
argTypes: {
variant: {
table: {
disable: true,
},
},
},
};
Ya tenemos nuestra primera historia en Storybook y podemos interactuar con ella. Sin embargo, si ejecutamos el comando Storybook, nuestros componentes aparecerán sin estilos. Esto es un problema conocido con TailwindCSS y Storybook. Para solucionarlo, necesitamos importar nuestros estilos en el entorno de Storybook para que sepa que estamos usando Tailwind.
Agreguemos el siguiente código a nuestro .storybook/preview.ts
:
import "../src/index.css"; // Importa el archivo principal de estilos CSS
const preview: Preview =
//...
Previsualiza Tu Componente 🖼️
Cuando ejecutes Storybook ahora (pnpm storybook
), verás una página de documentación con:
- Controles interactivos.
- Varios ejemplos.
- Documentación de props.
- Vista previa en vivo.
🎯 Conclusión: Tu proceso creando el Sistema de Diseño
¡Felicidades! 🎉 Acabas de construir la base de un sistema de diseño profesional utilizando algunas de las herramientas más potentes en el desarrollo web moderno.
Si quieres revisar el código en GitHub, aquí tienes el repositorio LINK
Recapitulemos lo que hemos logrado:
🏗️ Fundamentos Establecidos
- Storybook integrado para documentación y pruebas de componentes.
- TailwindCSS implementado para estilizado “utility-first”.
- Un sistema escalable de tokens de diseño creado.
- Un componente de encabezado construido con variantes de tipado seguro.
🎨 Arquitectura del Sistema de Diseño
- Componentes organizados usando principios de Diseño Atómico.
- Variantes de componentes con tipado seguro implementadas con CVA.
- Funciones de utilidad reutilizables para estilizado.
- Una estructura de proyecto mantenible.
📚 Mejores Prácticas de Desarrollo
- TypeScript utilizado para tipado seguro y una mejor DX (Developer Experience).
- CVA implementado para la gestión de variantes.
- Documentación completa de Storybook.
- Una arquitectura modular y escalable.
Próximos Pasos 🚀
Para seguir construyendo sobre esta base:
Expande Tu Librería de Componentes
- 🔘 Crea componentes de Botón con variantes.
- 📝 Construye elementos de Formulario.
- 🎨 Implementa diseños de Tarjeta (Card).
Agrega Funcionalidades Avanzadas
- 🌓 Soporte para modo
- 🌐 Internacionalización.
- 📱 Patrones de diseño responsivo.
Mejora la Experiencia del Desarrollador
- 🔄 Configura CI/CD para tu sistema de diseño.
- 📊 Agrega monitoreo de rendimiento.
- 📱 Crea variantes “mobile-first”.
Documentación y Mantenimiento
- 📘 Escribe documentación completa.
- 🧪 Agrega más cobertura de pruebas.
- 🔄 Configura actualizaciones regulares.
¿Encontraste esto útil? Sígueme en redes sociales (especialmente LinkedIn) para más tutoriales sobre desarrollo web, consejos de productividad y más.
💡 Consejos Pro para el Éxito:
- Empieza con componentes principales y expande gradualmente.
- Mantén un tipado seguro estricto en todo tu sistema.
- Documenta todo, especialmente los casos extremos (edge cases).
- Prueba los componentes a fondo antes de agregarlos a producción.
- Mantén tus tokens de diseño sincronizados con tu equipo de diseño.
¡Comparte tus implementaciones de sistemas de diseño conmigo! Me encantaría ver lo que construyes. No dudes en contactarme en redes sociales. 🌟