Utilidades de Tailwind
Hoja de referencia de utilidades principales — las clases más usadas y qué cambió en v4.
Receta
Tarjeta de referencia rápida — lista para copiar y pegar.
// Diseño
<div className="flex items-center justify-between gap-4">
<div className="grid grid-cols-3 gap-6">
<div className="absolute top-0 right-0">
<div className="sticky top-4">
// Tamaño
<div className="h-screen w-full max-w-lg min-h-0">
<div className="size-12"> {/* ancho Y alto */}
// Espaciado
<div className="p-4 px-6 py-2 pt-8">
<div className="m-auto mx-4 my-2 mt-0">
<div className="space-y-4"> {/* separación entre hijos */}
// Tipografía
<p className="text-sm font-medium leading-tight tracking-wide">
<p className="text-gray-600 text-balance truncate">
<p className="line-clamp-3 antialiased">
// Colores
<div className="bg-blue-500 text-white border-gray-200">
<div className="bg-blue-500/50"> {/* 50% de opacidad */}
// Bordes y radio
<div className="rounded-lg border border-gray-200 shadow-md">
<div className="ring-2 ring-blue-500 ring-offset-2">
<div className="divide-y divide-gray-100">
// Interactividad
<button className="cursor-pointer hover:bg-blue-600 focus:outline-none focus-visible:ring-2">
<div className="pointer-events-none select-none">Cuándo usarlo: Cada vez que escribes un componente. Estas cubren el 90% de las necesidades de estilo.
Ejemplo funcional
export function ProductCard({
name,
price,
image,
badge,
}: {
name: string;
price: number;
image: string;
badge?: string;
}) {
return (
<article className="group relative overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm transition-shadow hover:shadow-lg">
{/* Imagen */}
<div className="aspect-square overflow-hidden">
<img
src={image}
alt={name}
className="size-full object-cover transition-transform duration-300 group-hover:scale-105"
/>
</div>
{/* Insignia */}
{badge && (
<span className="absolute top-3 left-3 rounded-full bg-blue-500 px-2.5 py-0.5 text-xs font-semibold text-white">
{badge}
</span>
)}
{/* Contenido */}
<div className="space-y-1.5 p-4">
<h3 className="truncate text-sm font-medium text-gray-900">{name}</h3>
<p className="text-lg font-bold text-gray-900">
${price.toFixed(2)}
</p>
<button className="mt-2 w-full rounded-lg bg-gray-900 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-gray-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 active:scale-[0.98]">
Añadir al carrito
</button>
</div>
</article>
);
}Qué demuestra esto:
group+group-hover:*para efectos hover entre padre e hijoaspect-squarepara mantener la proporción de la imagensize-full(atajo dew-full h-full)transition-*para efectos hover suavesfocus-visible:para anillos de foco solo con tecladoactive:scale-[0.98]para feedback al presionartruncatepara desbordamiento de texto
Profundización
Cómo funciona
- Tailwind escanea tus archivos fuente en busca de nombres de clase y genera solo el CSS que usas
- Cada utilidad se mapea a una o varias propiedades CSS (p. ej.,
p-4=padding: 1rem) - Los valores arbitrarios usan sintaxis de corchetes:
w-[347px],bg-[#1da1f2],grid-cols-[200px_1fr] - Los modificadores se encadenan de izquierda a derecha:
dark:hover:bg-blue-600= modo oscuro + hover - v4 usa la pila CSS moderna —
@layer,@property, anidamiento nativo
Variaciones
Nuevo en v4 — cambios clave:
/* 1. inset-shadow e inset-ring (reemplaza hacks de box-shadow) */
.card { @apply inset-shadow-sm inset-ring inset-ring-gray-200; }
/* 2. La opacidad del color usa sintaxis con barra (igual que v3) */
.overlay { @apply bg-black/50; }
/* 3. Variante not-* */
.item { @apply not-last:border-b; }
/* 4. Variante in-* para el estado del padre */
.child { @apply in-[.open]:block; }
/* 5. Nuevas utilidades size-* */
.avatar { @apply size-10; /* = w-10 h-10 */ }
/* 6. text-balance y text-pretty */
.heading { @apply text-balance; }
.paragraph { @apply text-pretty; }Patrones de Flexbox:
// Contenido centrado
<div className="flex min-h-screen items-center justify-center">
// Diseño con barra lateral
<div className="flex">
<aside className="w-64 shrink-0" />
<main className="min-w-0 flex-1" />
</div>
// Espacio entre elementos con wrap
<div className="flex flex-wrap items-center justify-between gap-4">
// Pila con empuje por margin auto
<nav className="flex flex-col">
<a>Home</a>
<a>About</a>
<a className="mt-auto">Settings</a> {/* empujado hacia abajo */}
</nav>Patrones de Grid:
// Grid responsivo con auto-fill
<div className="grid grid-cols-[repeat(auto-fill,minmax(250px,1fr))] gap-4">
// Áreas nombradas
<div className="grid grid-cols-[250px_1fr] grid-rows-[auto_1fr_auto] [grid-template-areas:'sidebar_header''sidebar_main''sidebar_footer']">
// Subgrid (v4)
<div className="grid grid-cols-subgrid col-span-3">Notas de TypeScript
// Composición de utilidades con tipado seguro usando cva o clsx
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
function cn(...inputs: (string | undefined | false | null)[]) {
return twMerge(clsx(inputs));
}
// Uso
<div className={cn(
"rounded border p-4",
isActive && "border-blue-500 bg-blue-50",
disabled && "opacity-50 pointer-events-none",
)} />Errores comunes
-
El orden de clases no determina la especificidad —
p-4 p-2no garantiza que ganep-2. Ambas tienen la misma especificidad; el orden en el código fuente CSS decide. Solución: Usatailwind-mergepara resolver conflictos:twMerge("p-4 p-2")devuelve"p-2". -
Los valores arbitrarios necesitan pistas de tipo correctas —
bg-[--brand]es ambiguo. Solución: Usabg-[color:--brand]para indicarle a Tailwind que es un valor de color. -
min-w-0en hijos flex — Los hijos flex tienen por defectomin-width: auto, lo que provoca overflow. Solución: Añademin-w-0a los hijos flex que deban encogerse. -
truncatenecesita una restricción de ancho —truncatesin un ancho en el padre no hace nada. Solución: Asegúrate de que el elemento o un padre tenga un ancho omax-widthdefinido. -
space-y-*con hijos renderizados condicionalmente — Los hijos ocultos siguen recibiendo márgenes. Solución: Usagap-*con flex/grid en su lugar.
Alternativas
| Alternativa | Cuándo usarla | Cuándo no usarla |
|---|---|---|
| Estilos en línea | Valores dinámicos puntuales (p. ej., style={{ width: computed }}) | Tienes patrones estáticos y repetitivos |
| CSS Modules | Necesitas CSS con alcance para una biblioteca de componentes | Prefieres un flujo de trabajo utility-first |
| Styled Components | Quieres CSS-in-JS con theming dinámico | Quieres cero CSS en tiempo de ejecución |
| Panda CSS | Quieres tokens de utilidades con tipado seguro y cero runtime | Prefieres la DX basada en clases de Tailwind |
Preguntas frecuentes
¿Qué hace la utilidad size-12?
Establece tanto width como height en 3rem — un atajo de w-12 h-12.
¿Cómo aplicas un 50% de opacidad a un color de fondo?
Usa la sintaxis con barra: bg-blue-500/50. El número después de / es el porcentaje de opacidad.
¿Para qué sirve el patrón group / group-hover:?
- Añade
groupa un elemento padre - Usa
group-hover:*en los hijos para estilizarlos cuando el padre recibe hover - Útil para efectos hover en tarjetas donde varios hijos cambian a la vez
¿Por qué deberías usar focus-visible: en lugar de focus:?
focus-visible: solo se activa con foco de teclado, no con clics del ratón. Esto evita anillos de foco no deseados después de hacer clic en un botón.
¿Cómo escribes un valor arbitrario para una utilidad que Tailwind no incluye?
Usa la sintaxis de corchetes: w-[347px], bg-[#1da1f2], grid-cols-[200px_1fr].
Trampa: Escribiste p-4 p-2 esperando que gane p-2. ¿Por qué podría no ser así?
El orden de clases en la cadena className no determina la especificidad CSS. Ambas tienen la misma especificidad, así que el orden en el código fuente CSS decide. Usa twMerge("p-4 p-2") para resolver de forma fiable a p-2.
Trampa: truncate está en un elemento pero el texto no se trunca. ¿Por qué?
truncate requiere que el elemento o un padre tenga una restricción de width o max-width definida. Sin ella, no hay nada contra lo que truncar.
¿Por qué deberías añadir min-w-0 a los hijos flex?
Los hijos flex tienen por defecto min-width: auto, lo que impide que se encojan por debajo del tamaño de su contenido. min-w-0 permite un encogimiento correcto y evita overflow.
¿Qué es la utilidad cn() y cómo se tipa en TypeScript?
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
function cn(...inputs: (string | undefined | false | null)[]) {
return twMerge(clsx(inputs));
}Combina nombres de clase condicionales y resuelve conflictos de Tailwind.
¿Para qué se usan text-balance y text-pretty en v4?
text-balance— equilibra la longitud de las líneas en encabezados para que ninguna sea mucho más corta que otratext-pretty— evita palabras huérfanas al final de los párrafos
¿Cómo funciona el encadenamiento de modificadores (p. ej., dark:hover:bg-blue-600)?
Los modificadores se encadenan de izquierda a derecha. dark:hover:bg-blue-600 significa "en modo oscuro, al hacer hover, aplica bg-blue-600."
¿Qué patrón de TypeScript garantiza una composición segura de clases condicionales?
<div className={cn(
"rounded border p-4",
isActive && "border-blue-500 bg-blue-50",
disabled && "opacity-50 pointer-events-none",
)} />Los valores falsy se filtran con clsx antes de que twMerge resuelva los conflictos.
Relacionado
- Configuración — instalación y configuración de v4
- Responsive — breakpoints y container queries
- Modo oscuro — utilidades de modo oscuro
- Utilidades personalizadas — crear tus propias utilidades