Detalhes do pacote

css-variants

timphandev8.6kMIT2.1.0

A lightweight, flexible API for managing CSS class variants.

javascript, typescript, js, ts

readme (leia-me)

test license npm npm

css-variants

A lightweight, flexible API for managing CSS class variants and inline styles in JavaScript and TypeScript projects.

Features

  • 🎨 Dynamic class name generation with variant support
  • 💅 First-class inline styles support alongside class names
  • 🧩 Powerful slot-based variant system for complex components
  • 📦 Zero dependencies
  • 🔒 Fully type-safe with TypeScript
  • 🚀 Framework-agnostic
  • 🪶 Lightweight (~2KB gzipped)
  • 🔥 Strong tree-shaking support
  • ⚡️ Optimal runtime performance

Installation

# npm
npm install css-variants

# yarn
yarn add css-variants

# pnpm 
pnpm add css-variants

Core Utilities

css-variants provides four main utilities:

  • cv - Class Variants for managing single component class names
  • sv - Style Variants for managing single component inline styles
  • scv - Slot Class Variants for managing multiple slot class names
  • ssv - Slot Style Variants for managing multiple slot inline styles
  • cx - Utility for composing class names conditionally.

Class Variants (cv)

For managing class names for a single component:

import { cv } from 'css-variants'

const button = cv({
  base: 'font-bold rounded-lg',
  variants: {
    color: {
      primary: 'bg-blue-500 text-white',
      secondary: 'bg-gray-500 text-white' 
    },
    size: {
      sm: 'text-sm px-2 py-1',
      lg: 'text-lg px-4 py-2'
    }
  },
  compoundVariants: [
    {
      color: 'primary',
      size: 'lg',  
      className: 'uppercase'
    }
  ],
  defaultVariants: {
    color: 'primary',
    size: 'sm'
  }
})

// Usage
button() // => 'font-bold rounded-lg bg-blue-500 text-white text-sm px-2 py-1'

button({ size: 'lg' }) // => 'font-bold rounded-lg bg-blue-500 text-white text-lg px-4 py-2 uppercase'

button({ size: 'lg', className: 'custom' }) // => 'font-bold rounded-lg bg-blue-500 text-white text-lg px-4 py-2 uppercase custom'

Style Variants (sv)

For managing inline styles:

import { sv } from 'css-variants'

const button = sv({
  base: {
    fontWeight: 'bold',
    borderRadius: '8px'
  },
  variants: {
    color: {
      primary: {
        backgroundColor: 'blue',
        color: 'white'
      },
      secondary: {
        backgroundColor: 'gray',
        color: 'white'
      }
    }
  }
})

// Usage
button({ color: 'primary' })
// => { fontWeight: 'bold', borderRadius: '8px', backgroundColor: 'blue', color: 'white' }

button({
  color: 'secondary',
  style: { padding: '4px' },
})
// => { fontWeight: 'bold', borderRadius: '8px', backgroundColor: 'gray', color: 'white', padding: '4px' }

Slot Class Variants (scv)

For managing class names across multiple slots/elements:

import { scv } from 'css-variants'

const card = scv({
  slots: ['root', 'title', 'content'],
  base: {
    root: 'rounded-lg shadow',
    title: 'text-xl font-bold',
    content: 'mt-2'
  },
  variants: {
    size: {
      sm: {
        root: 'p-4',
        title: 'text-base'
      },
      lg: {
        root: 'p-6', 
        title: 'text-2xl'
      }
    }
  }
})

// Usage
card({ size: 'sm' })
// => {
//   root: 'rounded-lg shadow p-4',
//   title: 'text-xl font-bold text-base',
//   content: 'mt-2'
// }

card({
  size: 'lg',
  classNames: {
    content: 'custom',
  },
})
// => {
//   root: 'rounded-lg shadow p-6',
//   title: 'text-xl font-bold text-2xl',
//   content: 'mt-2 custom'
// }

Slot Style Variants (ssv)

For managing inline styles across multiple slots:

import { ssv } from 'css-variants'

const card = ssv({
  slots: ['root', 'title'],
  base: {
    root: { padding: '1rem' },
    title: { fontWeight: 'bold' }
  },
  variants: {
    size: {
      sm: {
        root: { maxWidth: '300px' },
        title: { fontSize: '14px' }
      },
      lg: {
        root: { maxWidth: '600px' },
        title: { fontSize: '18px' }
      }
    }
  }
})

// Usage
card({ size: 'sm' })
// => {
//   root: { padding: '1rem', maxWidth: '300px' },
//   title: { fontWeight: 'bold', fontSize: '14px' }
// }

card({
  size: 'lg',
  styles: {
    title: {
      color: 'red',
    },
  },
})
// => {
//   root: { padding: '1rem', maxWidth: '600px' },
//   title: { fontWeight: 'bold', fontSize: '18px', color: 'red' }
// }

Class Merger (cx)

Similar to clsx/classnames but with better TypeScript support.

import { cx } from 'css-variants'

// Basic usage
cx('foo', 'bar') // => 'foo bar'

// With conditions
cx('foo', { 
  'bar': true,
  'baz': false 
}) // => 'foo bar'

// With arrays
cx('foo', ['bar', 'baz']) // => 'foo bar baz'

// With nested structures
cx('foo', {
  bar: true,
  baz: [
    'qux',
    { quux: true }
  ]
}) // => 'foo bar qux quux'

// With falsy values (they're ignored)
cx('foo', null, undefined, false, 0, '') // => 'foo'

Advanced Features

Boolean Variants

Support for boolean variants to toggle styles conditionally:

import { cv } from 'css-variants'

const button = cv({
  variants: {
    disabled: {
      true: 'opacity-50 cursor-not-allowed'
    }
  }
})

button({ disabled: true }) // => 'opacity-50 cursor-not-allowed'

Compound Variants

Apply styles based on combinations of variants:

import { cv } from 'css-variants'

const button = cv({
  variants: {
    color: {
      primary: 'bg-blue-500',
      danger: 'bg-red-500'  
    },
    size: {
      sm: 'text-sm',
      lg: 'text-lg'
    }
  },
  compoundVariants: [
    {
      color: 'danger',
      size: 'lg',
      className: 'animate-pulse'
    }
  ]
})

button({ color: 'danger', size: 'lg' }) // => 'bg-red-500 text-lg animate-pulse'

Default Variants

Specify default variant values:

import { cv } from 'css-variants'

const button = cv({
  variants: {
    size: {
      sm: 'text-sm',
      lg: 'text-lg'  
    }
  },
  defaultVariants: {
    size: 'sm'
  }
})

button() // => 'text-sm'

Custom Class Name Resolver

Use your preferred class name utility:

import { cv } from 'css-variants'
import { clsx } from 'clsx'

const button = cv({
  base: 'btn',
  variants: {
    color: {
      primary: 'btn-primary'
    }
  },
  classNameResolver: clsx
})

TypeScript Support

Full TypeScript support with automatic type inference:

import { cv } from 'css-variants'

const button = cv({
  variants: {
    size: {
      sm: 'text-sm',
      lg: 'text-lg'
    }
  }
})

type ButtonProps = Parameters<typeof button>[0]
// => { size?: 'sm' | 'lg' | undefined }

Inspiration

This library is inspired by several excellent projects:

Contribute

If you would like to contribute to the project, please read how to contribute here CONTRIBUTING.md.

License

Licensed under the MIT License.

See MIT license for more information.