Skip to content

class-recipe

@lynstack/class-recipe maps a component’s variants to its class names, for any CSS approach. It has three functions, and one more to configure them:

  • cva creates a recipe for the class name of one element.
  • sva creates a slot recipe for the class names of several elements, such as a card’s root, header, and body.
  • cx joins class names, as a drop-in replacement for clsx.
  • createRecipes returns them with a join function such as twMerge, or with the cache turned off.
import { cva } from "@lynstack/class-recipe";
export const button = cva({
base: "inline-flex items-center rounded-md font-medium",
variants: {
tone: {
neutral: "bg-gray-100 text-gray-900",
danger: "bg-red-600 text-white",
},
size: {
sm: "h-8 px-3 text-sm",
md: "h-10 px-4",
},
},
defaultVariants: { size: "md" },
});

PlaygroundChoose the variants. The classes a choice adds light up.

tone
size
button({ tone: "neutral" })→ "inline-flex items-center rounded-md font-medium bg-gray-100 text-gray-900 h-10 px-4"
  • Fast. A recipe compiles its config once and caches the class name of each selection, so most calls are a lookup. It runs about 9 times as many calls per second as class-variance-authority (see Performance).
  • Type-safe. Variant names, options, and slots are inferred from the config. An unknown option or slot is a type error, and a variant without a default is required, so a component cannot forget to choose it.
  • Pluggable. Bring your own join function, such as twMerge, to resolve conflicting classes. It runs once per selection, not on every call.
  • Small. ES modules only and tree-shakable. Its one dependency is @lynstack/recipe, the engine it is built on, and Bundlephobia shows its size.

Use it to style components with class names: Tailwind CSS, CSS Modules, or any stylesheet. To map variants to values other than class names, such as style objects, use @lynstack/recipe, the engine class-recipe is built on.