Write variants as one line each and get the cva() call, the defaults and the VariantProps type, in the shape shadcn components use.
The result appears hereOne rule per line. base: for the classes every instance carries, then group: option = classes for each variant, and default: group=option for the defaults. Anything else on its own line is treated as more base classes.
Because the variants become a type. VariantProps reads the object back out, so the component's props are exactly the options you defined and a typo is a compile error rather than a missing class.
CVA composes the classes, cn() resolves the conflicts when a caller passes their own. The usual shape is cn(buttonVariants({ variant, size }), className), and the merge playground shows what that does.
2189 blocks and 1325 pieces for shadcn/ui and Tailwind, built on the same tokens these tools write. Install one with a command and the code is yours.
Browse the blocksNo signup for the tools. MIT for free blocks, commercial licence for Pro.