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.