Documentation
Installation

Installation

pnpm i class-variance-authority
Do I really have to write such a long package name?

Unfortunately, for a little bit longer, yes. Originally, the plan was to publish the package as cva, but this name was taken and marked as a "placeholder" (opens in a new tab).

On 2022/02/16, GitHub transferred NPM ownership of cva to Joe Bell (opens in a new tab). This shorter name will be used from v1 onwards.

In the meantime, you can always alias the package for your convenience…

  1. Alias the package with npm install (opens in a new tab)

    npm i cva@npm:class-variance-authority
  2. Then import like so:

    import { cva } from "cva";
     
    // …

Tailwind CSS

If you're a Tailwind user, here are some additional (optional) steps to get the most out of cva:

IntelliSense

You can enable autocompletion inside cva using the steps below:

  1. Install the "Tailwind CSS IntelliSense" Visual Studio Code extension (opens in a new tab)

  2. Add the following to your settings.json (opens in a new tab):

{
  "tailwindCSS.experimental.classRegex": [
    ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
  ]
}

Handling Style Conflicts

Although cva's API is designed to help you avoid styling conflicts, there's still a small margin of error.

If you're keen to lift that burden altogether, check out the wonderful tailwind-merge (opens in a new tab) package.

For bulletproof components, wrap your cva component with twMerge.

Example with tailwind-merge
import { cva, type VariantProps } from "class-variance-authority";
import { twMerge } from "tailwind-merge";
 
const buttonVariants = cva(["your", "base", "classes"], {
  variants: {
    intent: {
      primary: ["your", "primary", "classes"],
    },
  },
  defaultVariants: {
    intent: "primary",
  },
});
 
export interface ButtonVariants extends VariantProps<typeof buttonVariants> {}
 
export const button = (variants: ButtonVariants) =>
  twMerge(buttonVariants(variants));