You can merge one or more cva components into a single component using the composes property. This allows you to build complex components by shallowly merging base styles and variants from existing cva definitions. You can pass a single component directly or an array of multiple components.
Important: Pass components to composes as an inline array literal or one marked as const. Using a pre-declared, mutable array variable (e.g., const list = [a, b]) will cause the loss of tuple inference, which can lead to incorrect or missing variant types in the resulting component.
import { cva, type VariantProps } from "cva";
const box = cva({
base: "box box-border",
variants: {
margin: { 0: "m-0", 2: "m-2", 4: "m-4", 8: "m-8" },
padding: { 0: "p-0", 2: "p-2", 4: "p-4", 8: "p-8" },
},
defaultVariants: {
margin: 0,
padding: 0,
},
});
const root = cva({
base: "card rounded border-solid border-slate-300",
variants: {
shadow: {
md: "drop-shadow-md",
lg: "drop-shadow-lg",
xl: "drop-shadow-xl",
},
},
});
// Compose the components
export const card = cva({ composes: [box, root] });
export interface CardProps extends VariantProps<typeof card> {}
// Usage
card({ margin: 2, shadow: "md" });
// => "box box-border m-2 p-0 card rounded border-solid border-slate-300 drop-shadow-md"
card({ margin: 2, shadow: "md", class: "adhoc-class" });
// => "box box-border m-2 p-0 card rounded border-solid border-slate-300 drop-shadow-md adhoc-class"