Skip to content

CSS Variant Libraries Comparison

CSS variant libraries are JavaScript/TypeScript tools that help developers manage component styling through a variant-based API. Instead of writing complex conditional class logic, you define variants (like color, size, disabled) and the library generates the correct CSS classes or styles at runtime.

Popular CSS variant libraries include:

  • css-variants — Zero-dependency, type-safe variant composition (~1KB)
  • CVA (Class Variance Authority) — The original variant library (~2KB)
  • tailwind-variants — Tailwind-focused variant library (~5KB)

Featurecss-variantsCVAtailwind-variants
Bundle Size~1KB~2KB~5KB
Dependencies01 (clsx)1 (tailwind-merge)
TypeScriptFull inferenceFull inferenceFull inference
Single-element variantscv()cva()tv()
Multi-slot componentsscv()❌ Not built-intv() with slots
Inline style variantssv() / ssv()❌ Not built-in❌ Not built-in
Works without Tailwind

css-variants is engineered for performance. Here’s how it compares:

Scenariocss-variantsCVAWinner
Base class only23.2M ops/s21.2M ops/scss-variants (1.1x)
Compound variants (no match)4.2M ops/s1.1M ops/scss-variants (3.7x)
Compound variants (match)4.1M ops/s1.0M ops/scss-variants (3.9x)
Complex component5.1M ops/s0.7M ops/scss-variants (6.9x)
Scenariocss-variantstailwind-variantsWinner
Base class only23.1M ops/s6.4M ops/scss-variants (3.6x)
Single variant9.9M ops/s2.2M ops/scss-variants (4.5x)
Compound variants4.0M ops/s0.7M ops/scss-variants (5.4x)
Complex component5.2M ops/s0.5M ops/scss-variants (11x)
Slot-based component1.6M ops/s0.3M ops/scss-variants (6.3x)

Multi-slot (or multi-element) components like cards, modals, and dropdowns need styles for multiple parts (root, header, body, footer, etc.).

import { scv } from 'css-variants'
const card = scv({
slots: ['root', 'header', 'body', 'footer'],
base: {
root: 'rounded-lg border',
header: 'p-4 border-b',
body: 'p-4',
footer: 'p-4 border-t',
},
variants: {
variant: {
default: { root: 'border-gray-200' },
primary: { root: 'border-blue-500' },
},
},
})
// Returns object with class strings directly
const classes = card({ variant: 'primary' })
// classes.root, classes.header, classes.body, classes.footer

css-variants is the only library with built-in support for inline CSS style variants — useful for dynamic values, CSS custom properties, or React’s style prop.

import { sv } from 'css-variants'
const box = sv({
base: { display: 'flex', borderRadius: '8px' },
variants: {
size: {
sm: { padding: '8px', width: '100px' },
lg: { padding: '24px', width: '300px' },
},
},
})
// Returns a style object, not class names
box({ size: 'lg' })
// => { display: 'flex', borderRadius: '8px', padding: '24px', width: '300px' }

Use cases for style variants:

  • Dynamic CSS values that can’t be utility classes
  • CSS custom properties / CSS variables
  • Canvas/SVG styling
  • Third-party library integrations expecting style objects

  • Smallest bundle size (~1KB minified + gzipped)
  • Best performance (3-11x faster than alternatives)
  • Zero dependencies (no clsx, no tailwind-merge bundled)
  • Inline style variants (sv and ssv functions)
  • Built-in slot support without separate functions
  • Framework-agnostic solution (React, Vue, Svelte, Solid, vanilla JS)
  • Works with any CSS approach (Tailwind, CSS Modules, vanilla CSS, CSS-in-JS)
  • Established ecosystem (more tutorials, examples)
  • Familiarity (if your team already uses it)
  • Simple API (single function, no slots)
  • Built-in tailwind-merge (automatic class conflict resolution)
  • Component composition (extend property for inheritance)
  • Tailwind-specific features (responsiveVariants)

Already using another library? Migration is straightforward:


Yes. css-variants is a drop-in alternative to CVA (Class Variance Authority) with a nearly identical API. The main differences are:

  • Base classes go in a base property instead of the first argument
  • Use className instead of class in compound variants
  • Additional features: slot variants (scv), style variants (sv, ssv)

Is css-variants a tailwind-variants alternative?

Section titled “Is css-variants a tailwind-variants alternative?”

Yes. css-variants can replace tailwind-variants with better performance and smaller bundle size. Key differences:

  • Use cv for single-element, scv for slots (instead of tv for both)
  • No built-in tailwind-merge (add via classNameResolver if needed)
  • No extend property (use object spreading for composition)

Can I use css-variants without Tailwind CSS?

Section titled “Can I use css-variants without Tailwind CSS?”

Absolutely yes. css-variants is CSS-framework agnostic. It works with:

  • Vanilla CSS class names
  • CSS Modules
  • CSS-in-JS solutions (styled-components, emotion)
  • Any utility CSS framework (Bootstrap, Bulma, UnoCSS)
  • No CSS at all (just organizing class strings)

What’s the difference between cv, scv, sv, and ssv?

Section titled “What’s the difference between cv, scv, sv, and ssv?”
FunctionOutputUse Case
cv()Class stringSingle-element components
scv()Object of class stringsMulti-slot components (card, modal)
sv()Style objectSingle-element inline styles
ssv()Object of style objectsMulti-slot inline styles

css-variants is a modern, performance-focused CSS variant library that serves as an excellent alternative to both CVA and tailwind-variants. It offers:

  • 3-11x better performance than alternatives
  • ~1KB bundle size with zero dependencies
  • Full TypeScript support with type inference
  • Unique features like style variants and optimized slot handling
  • Framework-agnostic design that works everywhere

→ Ready to start? Get started with css-variants