Variants
This content is for Beta. Switch to the latest version for up-to-date documentation.
Creating variants
Section titled “Creating variants”To kick things off, let’s build a “basic” button component, using cva to handle our variant’s classes
import { cva } from "cva";
const button = cva({ base: "rounded border font-semibold", // **or** // base: ["font-semibold", "border", "rounded"], variants: { intent: { primary: "border-transparent bg-blue-500 text-white hover:bg-blue-600", // **or** // primary: [ // "bg-blue-500", // "text-white", // "border-transparent", // "hover:bg-blue-600", // ], secondary: "border-gray-400 bg-white text-gray-800 hover:bg-gray-100", }, size: { small: "px-2 py-1 text-sm", medium: "px-4 py-2 text-base", }, }, compoundVariants: [ { intent: "primary", size: "medium", class: "uppercase", // **or** if you're a React.js user, `className` may feel more consistent: // className: "uppercase" }, ], defaultVariants: { intent: "primary", size: "medium", },});
button();// => "rounded border font-semibold border-transparent bg-blue-500 text-white hover:bg-blue-600 px-4 py-2 text-base uppercase"
button({ intent: "secondary", size: "small" });// => "rounded border font-semibold border-gray-400 bg-white text-gray-800 hover:bg-gray-100 px-2 py-1 text-sm"Compound variants
Section titled “Compound variants”Variants that apply when multiple other variant conditions are met.
import { cva } from "cva";
const button = cva({ base: "…", variants: { intent: { primary: "…", secondary: "…" }, size: { small: "…", medium: "…" }, }, compoundVariants: [ // Applied via: // `button({ intent: "primary", size: "medium" })` { intent: "primary", size: "medium", class: "…", }, ],});Targeting multiple variant conditions
Section titled “Targeting multiple variant conditions”import { cva } from "cva";
const button = cva({ base: "…", variants: { intent: { primary: "…", secondary: "…" }, size: { small: "…", medium: "…" }, }, compoundVariants: [ // Applied via: // `button({ intent: "primary", size: "medium" })` // or // `button({ intent: "secondary", size: "medium" })` { intent: ["primary", "secondary"], size: "medium", class: "…", }, ],});Disabling variants
Section titled “Disabling variants”To disable a variant completely, provide an option with a value of null.
If you’re stuck on naming, we recommend setting an explicit "unset" option (similar to the CSS keyword).
import { cva } from "cva";
const button = cva({ base: "button", variants: { intent: { unset: null, primary: "button--primary", secondary: "button--secondary", }, },});
button({ intent: "unset" });// => "button"Internal variants
Section titled “Internal variants”A variant name prefixed with _ is internal: it’s still declarable in variants, drivable via defaultVariants, and matchable in compoundVariants, but hidden from the component’s props type and from getSchema.
Use this for a variant an author drives (state, composition wiring), not one a consumer of the component should set directly.
import { cva } from "cva";
const button = cva({ base: "button", variants: { _intent: { primary: "button--primary", secondary: "button--secondary", }, size: { small: "button--small", medium: "button--medium", }, }, defaultVariants: { _intent: "primary", size: "medium", },});
button({ size: "small" });// => "button button--primary button--small"
button({ _intent: "secondary" });// Type error: object literal may only specify known properties, and// '_intent' does not exist in type '{ size?: "small" | "medium" }'A composed-only internal variant is hidden from the composer’s props too. To change its default from the composer, redeclare it locally: the same rule applies to any composed-only variant (see Extending variants).
const base = cva({ variants: { _tone: { quiet: "tone-quiet", loud: "tone-loud" }, }, defaultVariants: { _tone: "quiet" },});
const card = cva({ composes: base, variants: { _tone: { loud: "loud-local" } }, defaultVariants: { _tone: "loud" },});
card();// => "tone-loud loud-local"