Skip to content

API Reference

This content is for Beta. Switch to the latest version for up-to-date documentation.

Builds a cva component

import { cva } from "cva";
const component = cva(options);

A call reads only the props you pass it, plus the cx you gave defineConfig, which stays live. Getters with side effects, and changing the props object while the call is running, are unsupported.

  1. options
    • base: the base class name (string, string[] or other clsx value)
    • variants: your variants schema
    • compoundVariants: variants based on a combination of previously defined variants
    • defaultVariants: set default values for previously defined variants
    • composes: shallow merge one or more other cva components into this one, as a single component or an array (see Composing Components)

A cva component function

Concatenates class names (an alias of clsx; swap in your own concatenator via cva/config).

import { cx } from "cva";
cx("button", "rounded");

See the clsx documentation for examples of strings, arrays, and conditional objects. If you configure a different concatenator, follow its documentation for supported inputs; see handling class conflicts for the Tailwind CSS options.

  • Zero or more class values. The preset accepts clsx values; cva/config uses the configured concatenator’s grammar

string

Custom Tailwind CSS variants, for use with or without cva. Import it after Tailwind CSS to add the base: variant.

Marks a utility as a component default. Ordinary utilities override base: utilities through the CSS cascade, and base: utilities still override browser defaults and Tailwind’s base and components layers.

See cva/tailwindcss for setup and limitations.

Extracts a plain-object schema (variant names, possible values, and default values) from a cva component. Use it to generate Storybook controls, documentation, or any other UI that reads a component’s variants without re-declaring them. See Tools for use cases.

import { cva } from "cva";
import { getSchema } from "cva/tools";
const button = cva({
base: "button",
variants: {
intent: { primary: "button--primary", secondary: "button--secondary" },
disabled: { true: "button--disabled", false: "button--enabled" },
},
defaultVariants: { intent: "primary", disabled: false },
});
getSchema(button);
// => {
// intent: { values: ["primary", "secondary"], defaultValue: "primary" },
// disabled: { values: [true, false], defaultValue: false },
// }

getSchema omits internal variants or variants that have no values (e.g. variants: { empty: {} }).

component: a component created by cva (including components composed via composes)

An object keyed by variant name. Each entry has:

  • values: a readonly array of the variant’s possible values
  • defaultValue: present only if the variant has a defaultVariants entry

The cva package is a preset: cva and cx use clsx. cva/config is the same engine without a configured concatenator.

Generate cva and cx functions based on your preferred configuration.

Store in a cva.config.ts file, and import across your project.

cva.config.ts
import { defineConfig } from "cva/config";
export const { cva, cx } = defineConfig(options);
  1. options
    • cx (required): the class name concatenator used by cva and cx
      • It owns the class name grammar: cva passes composed outputs, base, matched variant and compound-variant values, and class/className through verbatim, one argument each.
      • Custom callbacks must accept empty calls, variadic inputs, and composed component strings.
      • The authoring surface adopts its parameter type: twMerge rejects object syntax, while clsx keeps the full clsx-flavored ClassValue grammar.
      • See Handling class conflicts for CSS defaults, cn, and tailwind-merge examples.

Use clsx/lite only when every authored value is a string and you do not need conflict resolution. Its runtime ignores arrays, objects, and numbers even though its published types accept them. Annotate a string-only wrapper so cva rejects those values too:

import { defineConfig } from "cva/config";
import { clsx as clsxLite } from "clsx/lite";
export const { cva, cx } = defineConfig({
cx: (...inputs: string[]) => clsxLite(...inputs),
});