How the project folders fit together, and the rule every component in this bundle follows so it stays customizable.
Every component in app/components/ui accepts a className prop and runs it through cn()before applying it — never edit a primitive's own source just to change how one usage looks. Pass the override instead:
<Button className="bg-red-500 hover:bg-red-600">Danger</Button>This matters because Tailwind classes are just strings — if a component naively did `bg-foreground ${className}`, you'd end up with "bg-foreground bg-red-500" in the DOM. Both classes exist in Tailwind's generated stylesheet, so which one actually wins depends on CSS source order, not on which one you meant to override — a real bug waiting to happen once styles get complex. cn() (clsx + tailwind-merge) fixes this by detecting that both classes touch the same CSS property and keeping only the later one, so the prop you pass in always wins predictably.
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Rule of thumb: edit a primitive's source only when changing its default, global look. For a one-off look in a single usage, pass className instead.