Migration from CVA (class-variance-authority)
css-variants has a similar API to CVA (Class Variance Authority), making migration straightforward.
Key Differences
Section titled “Key Differences”| Feature | CVA | css-variants |
|---|---|---|
| Base styles | First argument | base property |
| Compound class key | class | className |
| Custom merger | class in call | classNameResolver in config |
| Slot variants | Not built-in | scv function |
| Style variants | Not built-in | sv and ssv functions |
Basic Migration
Section titled “Basic Migration”import { cva } from 'class-variance-authority'
const button = cva('btn base-styles', { variants: { color: { primary: 'bg-blue-600 text-white', secondary: 'bg-gray-200 text-gray-900', }, size: { sm: 'px-3 py-1 text-sm', lg: 'px-6 py-3 text-lg', }, }, defaultVariants: { color: 'primary', size: 'sm', },})import { cv } from 'css-variants'
const button = cv({ base: 'btn base-styles', // Move to 'base' property variants: { color: { primary: 'bg-blue-600 text-white', secondary: 'bg-gray-200 text-gray-900', }, size: { sm: 'px-3 py-1 text-sm', lg: 'px-6 py-3 text-lg', }, }, defaultVariants: { color: 'primary', size: 'sm', },})Compound Variants
Section titled “Compound Variants”const button = cva('btn', { variants: { /* ... */ }, compoundVariants: [ { color: 'primary', size: 'lg', class: 'shadow-lg', // CVA uses 'class' }, ],})const button = cv({ base: 'btn', variants: { /* ... */ }, compoundVariants: [ { color: 'primary', size: 'lg', className: 'shadow-lg', // css-variants uses 'className' }, ],})Runtime Class Overrides
Section titled “Runtime Class Overrides”button({ color: 'primary', class: 'mt-4' })button({ color: 'primary', className: 'mt-4' })Type Extraction
Section titled “Type Extraction”import { type VariantProps } from 'class-variance-authority'
const button = cva('btn', { /* ... */ })
type ButtonProps = VariantProps<typeof button>const button = cv({ /* ... */ })
type ButtonProps = Parameters<typeof button>[0]New Features in css-variants
Section titled “New Features in css-variants”After migrating, you can take advantage of features not available in CVA:
Slot Variants
Section titled “Slot Variants”For multi-element components, use scv to define styles for each slot:
import { scv } from 'css-variants'
const card = scv({ slots: ['root', 'header', 'content', 'footer'], base: { root: 'rounded-lg border', header: 'p-4 border-b', content: 'p-4', footer: 'p-4 border-t', }, variants: { variant: { default: { root: 'border-gray-200' }, primary: { root: 'border-blue-200' }, }, },})
// Usageconst classes = card({ variant: 'primary' })// classes.root, classes.header, classes.content, classes.footerStyle Variants
Section titled “Style Variants”For inline CSS styles (React’s style prop), use sv:
import { sv } from 'css-variants'
const box = sv({ base: { display: 'flex', borderRadius: '8px', }, variants: { size: { sm: { padding: '8px' }, lg: { padding: '24px' }, }, },})
// Returns CSS style object instead of class stringbox({ size: 'lg' }) // => { display: 'flex', borderRadius: '8px', padding: '24px' }Migration Checklist
Section titled “Migration Checklist”- Replace
cvaimports withcvfromcss-variants - Move first argument (base classes) to
baseproperty - Change
classtoclassNamein compound variants - Change
classtoclassNamein runtime overrides - Update
VariantPropstype extraction to useParameters<typeof fn>[0] - (Optional) Convert multi-element components to use
scv - (Optional) Convert inline style components to use
svorssv