En el mundo de desarrollo moderno, Tailwind CSS se ha establecido como una de las herramientas de estilado más utilizadas.
A diferencia de las librerías de componentes prefabricados (como Material UI o Bootstrap) o de las metodologías de CSS tradicional (BEM, CSS Modules), Tailwind opera bajo el concepto de Utility-First.
Tailwind nos proporciona un conjunto extenso de clases de bajo nivel que mapean directamente a propiedades CSS, permitiéndonos construir diseños personalizados directamente desde el JSX.
En este artículo, vamos a ver cómo integrar Tailwind CSS en un proyecto de React usando Vite, cómo configurarlo correctamente y que ventajas (y desventajas) tiene usarlo.
- Sin cambiar de ficheros: No tienes que saltar entre
Componente.jsxyComponente.css. Todo está en el mismo archivo. - Sistema de diseño: Evita el caos de los “números mágicos”. No puedes poner
margin: 13px. Tienes que ceñirte a la escala (m-3,m-4), lo que garantiza consistencia visual. - Adiós al “Dead Code”: Gracias a su motor JIT (Just-In-Time), solo se genera el CSS de las clases que realmente usas.
- Legibilidad del HTML: El JSX se llena de clases, dificultando ver la estructura del documento a simple vista.
- CSS Estándar: Aprendes una sintaxis propietaria (
py-2) en lugar de propiedades estándar (padding-top/bottom). Si Tailwind desaparece mañana, tu conocimiento de sus clases no sirve de mucho. - Falta de originalidad: Todas las aplicaciones parecen iguales.
Instalación en Vite
La integración actual en Vite se realiza a través de un plugin nativo, lo que elimina la necesidad de archivos de configuración de JavaScript complejos (que antes hacian falta).
En las nuevas versiones, sólo tenemos que instalar el paquete core y el plugin específico para Vite.
npm install tailwindcss @tailwindcss/vite
Configuración del Plugin
Ahora, en el archivo vite.config.js (o .ts), importamos y registramos el plugin. Esto permite que Vite procese las clases de Tailwind durante el desarrollo y el build.
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite' // 1. Importar
export default defineConfig({
plugins: [
react(),
tailwindcss(), // 2. Añadir al array
],
})
Tailwind utiliza un motor JIT (Just-In-Time). Esto significa que escanea nuestros archivos de código en busca de nombres de clases y genera un archivo CSS solo con las clases que hemos utilizado.
Construyendo un Componente
Vamos a rehacer nuestro famoso botón, pero esta vez con utilidades.
export default function BotonTailwind() {
return (
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Click me
</button>
);
}
Analicemos qué está pasando:
bg-blue-500: Fondo azul (tono medio).hover:bg-blue-700: Pseudo-clases integradas. Al pasar el ratón, oscurece el fondo.py-2 px-4: Padding vertical y horizontal.rounded: Bordes redondeados.
Fijaos en la velocidad de desarrollo. No he escrito ni una línea de CSS, no he creado archivos nuevos, y tengo mis estilos, incluida gestión de estados (hover).
Gestión de clases dinámicas
El problema de Tailwind es que el atributo className se suele volver kilométrico y difícil de leer, especialmente cuando metemos lógica condicional con Template Literals.
// ❌ Difícil de leer
<div className={`p-4 border ${isActive ? 'bg-blue-100 border-blue-500' : 'bg-gray-100 border-gray-300'}`}>
Por esto es habitual usar dos herramientas casi obligatorias:
- clsx: Para construir cadenas de clases condicionales.
- tailwind-merge: Para resolver conflictos de clases (ej: si intentamos sobrescribir un p-4 con un p-8, asegura que gane el último).
Instalamos las utilidades:
npm install clsx tailwind-merge
Creamos una función helper (usualmente en src/lib/utils.js):
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs) {
return twMerge(clsx(inputs));
}
Ahora podemos crear componentes que acepten clases externas y variantes de forma limpia:
import { cn } from "../lib/utils";
export default function Button({ className, variant = "primary", children, ...props }) {
return (
<button
className={cn(
// 1. Clases base (siempre se aplican)
"py-2 px-4 rounded font-semibold transition-colors focus:outline-none",
// 2. Variantes condicionales
variant === "primary" && "bg-blue-600 text-white hover:bg-blue-700",
variant === "secondary" && "bg-gray-200 text-gray-800 hover:bg-gray-300",
variant === "danger" && "bg-red-500 text-white hover:bg-red-600",
// 3. Clases externas (permite al padre añadir márgenes o anchos)
className
)}
{...props}
>
{children}
</button>
);
}
Este patrón nos permite mantener la flexibilidad de Tailwind encapsulada dentro de componentes React.
Reutilización y extracción
Otra duda frecuente al usar clases de utilidad es cómo evitar la repetición de código, sobre todo con clases larguísimas que apenas te caben en la pantalla.
En el contexto de React y Tailwind, la solución que se suele decir es que crees un componente por el elemento. Es decir, que en lugar de repetir clases:
// ❌ Repetitivo y difícil de mantener
<img className="rounded-full w-16 h-16 border-2 border-white" src="..." />
<img className="rounded-full w-16 h-16 border-2 border-white" src="..." />
Te crees un componente,
// ✅ Abstracción mediante React
function Avatar({ src }) {
return <img className="rounded-full w-16 h-16 border-2 border-white" src={src} />;
}
La clase sigue siendo insufriblemente larga, pero al menos ya solo la ves una vez 🤭.
¿Tailwind o CSS Modules?
No debemos casarnos con herramientas, sino elegir la adecuada para cada contexto. Personalmente prefiero el estándard, pero ambos son útiles a su manera.
Usa Tailwind si
- Necesitas iterar muy rápido (prototipado, MVPs).
- Trabajas en un equipo donde cada uno usa un
greydiferente y necesitas forzar consistencia. - No te importa tener el HTML “sucio” a cambio de velocidad de desarrollo.
Quédate con CSS Modules si
- Te gusta CSS: Quieres control total sobre tus selectores, animaciones complejas y la cascada.
- Valoras la limpieza del código: Quieres que tu JSX sea semántico y legible.
- Quieres mantener tu conocimiento alineado con los estándares web (W3C) y no con una librería específica.
