Tailwind CSS in Production · Missing and Wrong Styles
The Button That Ignored Its Override
A shared Button component accepted extra classes, but passing p-2 or bg-red-600 did nothing: conflicting utilities are decided by CSS order, not class order.
Scenario
Example team: a design-system Button has px-4 py-2 bg-indigo-600 and appends props.className. A feature team needs a compact red delete button and passes className="px-2 py-1 bg-red-600".
What you see in production
The delete button is still indigo and still large. Developers add !important (bg-red-600!), then more, and the component becomes impossible to reason about.
The naive code
const Button = ({ className = "", ...props }) => (
<button className={`rounded-lg px-4 py-2 bg-indigo-600 text-white ${className}`} {...props} />
);
Reproduce it
Both buttons below have both colours in their class list, in opposite orders. They look the same:
<div class="flex gap-4 p-6">
<button class="rounded-lg bg-indigo-600 bg-red-600 px-4 py-2 text-white">indigo then red</button>
<button class="rounded-lg bg-red-600 bg-indigo-600 px-4 py-2 text-white">red then indigo</button>
<button class="rounded-lg bg-red-600 px-2 py-1 text-sm text-white">merged: only red, compact</button>
</div>
Root cause
When two utilities set the same property, the one later in the generated stylesheet wins, and Tailwind sorts utilities by its own rules, not by the order in your class attribute. Appending classes can't reliably override a component's defaults.
The fix
- Merge class lists with tailwind-merge (
twMerge("px-4 py-2 bg-indigo-600", "px-2 py-1 bg-red-600")keeps only the last of each conflicting group). - Better still, give the component variants (
variant="danger" size="sm") with complete class strings, for example usingcva(class-variance-authority). - Reserve
!(important) for real edge cases.
Trade-offs
- tailwind-merge adds a small runtime cost and must know your custom theme utilities (configure it if you add
@themetokens). - Variants limit flexibility on purpose; that's what keeps a design system consistent.
Detect it in production
- Review components that concatenate
classNamewithout a merge function. - Search for
!important utilities; a growing count is a sign of override fights.
Key points
- Conflicting utilities resolve by stylesheet order, not attribute order.
- Merge with tailwind-merge or expose explicit variants.
!importantis a symptom, not a fix.
Practice questions
If an element has class="p-4 p-2", which padding applies and why?
Answer
Whichever utility appears later in the generated CSS, which Tailwind decides, not the order in the class attribute. Avoid conflicting utilities on one element; merge them with tailwind-merge or use variants.
Open in the app to mark lessons complete, take notes and track your progress.