Compose components
Work with variants and cn()
Use declared variants for repeated visual states and merge occasional caller classes without creating contradictory style combinations.
8 minute lesson
Generated components commonly use a variant utility and a cn() helper that combines conditional Tailwind classes and resolves conflicts.
Add a named variant when a visual state is reused and belongs to the component API. Pass className for a local layout adjustment. Do not make every one-off spacing choice a permanent variant, and do not let arbitrary classes erase required focus, disabled, or sizing behavior without review.
Variants work best as a small matrix of stable dimensions such as intent and size. If “compact destructive toolbar button on the dashboard” becomes one variant name, layout and product context have leaked into the primitive. Keep placement with the caller and meaning with the component.
Class merging is convenient because later conflicting utilities can win. That is also the risk: a caller can silently replace padding, foreground color, focus ring, or disabled opacity. Decide which classes are intentionally overridable and test the complete variant matrix after changing the merge order.
Inspect the Button variants and write down their public dimensions. Add one restrained success variant, use it twice, and use className only for surrounding layout. Render every size against every intent, including focus and disabled states, then try one conflicting class to see exactly what cn() resolves.
Lesson completed