Critical Patterns
Class Merging (REQUIRED)
import { clsx } from 'clsx'; import { twMerge } from 'tailwind-merge';
// ✅ ALWAYS: Use cn() utility for class merging function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }
// Usage <div className={cn( "base-classes", condition && "conditional-classes", className )} />
Component Variants (REQUIRED)
import { cva, type VariantProps } from 'class-variance-authority';
// ✅ Use CVA for variant management const buttonVariants = cva( "inline-flex items-center rounded-md font-medium transition-colors", { variants: { variant: { primary: "bg-blue-600 text-white hover:bg-blue-700", secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200", ghost: "hover:bg-gray-100", }, size: { sm: "h-8 px-3 text-sm", md: "h-10 px-4 text-base", lg: "h-12 px-6 text-lg", }, }, defaultVariants: { variant: "primary", size: "md", }, } );
interface ButtonProps extends VariantProps<typeof buttonVariants> { children: React.ReactNode; }
function Button({ variant, size, children }: ButtonProps) { return ( <button className={buttonVariants({ variant, size })}> {children} </button> ); }
Decision Tree
Need dynamic classes? → Use clsx/cn utility Need variants? → Use CVA Need conditional? → Use clsx with conditions Need to override? → Use tailwind-merge
Code Examples
Conditional Classes
<button className={cn( "px-4 py-2 rounded", isActive ? "bg-blue-600 text-white" : "bg-gray-200", disabled && "opacity-50 cursor-not-allowed" )}
Click me </button>