Lesson 23 / 25
Conditional Classes and Conflicts
clsx and tailwind-merge.
Which class wins?
When two utilities set the same property (p-2 and p-4), the winner depends on their order in the generated stylesheet, not their order in the class attribute, so passing an override through className may not work. Libraries help: clsx builds class strings conditionally, and tailwind-merge resolves conflicts so the last conflicting class wins. Many component libraries combine them in a cn() helper.
A cn() helper
Combining clsx and tailwind-merge (community libraries).
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs) {
return twMerge(clsx(inputs));
}
// cn("px-4 py-2 bg-cyan-600", isActive && "bg-cyan-800", "px-6")
// -> padding px-6 and bg-cyan-800 win when isActive is trueDesign props instead of raw overrides
A size="lg" prop is clearer and safer than letting callers pass arbitrary conflicting classes.
Quick check: What decides which of two conflicting utilities wins without tooling?
- Their order in the generated CSS
- Their order in the class attribute
- Alphabetical order
- The longer class name
Answer
Their order in the generated CSS — Use tailwind-merge for predictable overrides.