css-variants is no longer maintained. Use @lynstack/class-recipe: faster, stricter types, and React Native support. Migrate →
No longer maintained. Migrate to class-recipe →
css-variants is no longer maintained. Use @lynstack/class-recipe: faster, stricter types, and React Native support. Migrate →
No longer maintained. Migrate to class-recipe →
Variants are named groups of style options. Each variant has a set of possible values that map to different CSS classes.
Define variants as an object where keys are variant names and values map option names to CSS classes:
import { cv } from 'css-variants'
const alert = cv({ variants: { variant: { info: 'bg-blue-100 text-blue-900', warning: 'bg-yellow-100 text-yellow-900', error: 'bg-red-100 text-red-900', }, },})
alert({ variant: 'error' }) // => 'bg-red-100 text-red-900'Components can have any number of variants:
const button = cv({ variants: { color: { primary: 'bg-blue-600 text-white', secondary: 'bg-gray-200 text-gray-900', }, size: { sm: 'px-3 py-1.5 text-sm', md: 'px-4 py-2 text-base', lg: 'px-6 py-3 text-lg', }, rounded: { none: 'rounded-none', sm: 'rounded', full: 'rounded-full', }, },})
button({ color: 'primary', size: 'lg', rounded: 'full' })// => 'bg-blue-600 text-white px-6 py-3 text-lg rounded-full'Variant values support multiple formats:
const badge = cv({ variants: { color: { gray: 'bg-gray-100 text-gray-800', red: 'bg-red-100 text-red-800', }, },})const container = cv({ variants: { spacing: { normal: ['py-12', 'gap-6'], loose: ['py-16', 'gap-8'], }, },})const card = cv({ variants: { interactive: { true: { 'cursor-pointer': true, 'hover:shadow-lg': true }, false: {}, }, },})const container = cv({ base: ['max-w-7xl', 'mx-auto', { 'px-4': true, 'sm:px-6': true }], variants: { spacing: { tight: ['py-8', 'gap-4'], normal: ['py-12', 'gap-6'], loose: ['py-16', 'gap-8'], }, },})All variants are optional by default. If you don’t pass a value and there’s no default, the variant won’t contribute any classes:
const text = cv({ variants: { weight: { normal: 'font-normal', bold: 'font-bold', }, },})
text() // => '' (no classes)text({ weight: 'bold' }) // => 'font-bold'