CVA (class-variance-authority)
Para gestionar variantes de estilos (tamaño, color, estado) de tus componentes sin acumular condicionales de clases.
Librería de TypeScript para crear variantes de componentes de UI con clases CSS de forma tipada.
Notas y contexto
Qué es
CVA (class-variance-authority) es una pequeña librería de TypeScript creada por Joe Bell que ayuda a construir variantes de componentes de interfaz basadas en clases CSS, con seguridad de tipos. A diferencia de soluciones CSS-in-JS como Stitches o Vanilla Extract, trabaja con CSS tradicional, por lo que encaja perfectamente con Tailwind CSS, CSS Modules o tus propias hojas de estilo. Es open source con licencia Apache-2.0.
Para qué sirve
- Definir las distintas variantes visuales de un componente (por ejemplo,
intent: primary/secondaryosize: small/medium) en un único lugar. - Componer dinámicamente las clases CSS de un componente a partir de sus props sin escribir cadenas de condicionales.
- Aplicar estilos combinados con
compoundVariantscuando coinciden varias condiciones a la vez. - Establecer valores por defecto con
defaultVariantspara que el componente funcione aunque no le pases props. - Obtener autocompletado y comprobación de tipos de las variantes válidas gracias a la inferencia de TypeScript.
Cuándo usarlo
Es ideal cuando construyes un sistema de diseño o una biblioteca de componentes con Tailwind CSS y quieres organizar las variantes de forma mantenible y tipada. Si tu proyecto es pequeño y solo necesitas concatenar clases condicionalmente, quizá te baste con clsx o classnames. CVA aporta valor cuando hay varias dimensiones de variantes que combinar y quieres evitar el desorden de clases.
Ejemplo
Instalación:
npm install class-variance-authority
Definir un botón con variantes y usarlo:
// components/button.ts
import { cva } from 'class-variance-authority';
const button = cva(['font-semibold', 'border', 'rounded'], {
variants: {
intent: {
primary: ['bg-blue-500', 'text-white', 'border-transparent'],
secondary: ['bg-white', 'text-gray-800', 'border-gray-400'],
},
size: {
small: ['text-sm', 'py-1', 'px-2'],
medium: ['text-base', 'py-2', 'px-4'],
},
},
defaultVariants: {
intent: 'primary',
size: 'medium',
},
});
button({ intent: 'secondary', size: 'small' });
// => "font-semibold border rounded bg-white text-gray-800 border-gray-400 text-sm py-1 px-2"
Puntos clave
- Tipado completo: TypeScript infiere las variantes válidas y avisa si pasas un valor inexistente.
- Funciona con CSS tradicional, así que se integra de forma natural con Tailwind CSS, CSS Modules o estilos propios.
- Soporta
compoundVariantspara estilos que dependen de la combinación de varias variantes. - Agnóstica del framework: hay ejemplos para React, Vue, Svelte, Astro y 11ty.
- Muy ligera, sin dependencias pesadas, y con licencia Apache-2.0.
Ten en cuenta
CVA solo genera la cadena de clases CSS; no incluye un componente ni resuelve conflictos entre clases de Tailwind. Para eso suele combinarse con tailwind-merge (por ejemplo, mediante la utilidad cx/twMerge). La versión 1.0 está en beta con documentación aparte; si necesitas la API estable, usa la rama actual (0.7.x). Si no manejas variantes complejas, una utilidad más simple como clsx puede ser suficiente.