Best Practices and Common Mistakes
Keeping class lists readable, avoiding common pitfalls, and using tooling to sort and lint utility classes automatically.
3 phút đọc
Tailwind is easy to start with and easy to make a mess with. Most of the friction people blame on "too many classes" actually comes from a handful of avoidable habits.
Let a tool sort your classes, don't do it by hand
<!-- Before: order is whatever you happened to type -->
<div class="text-white p-4 flex bg-blue-600 rounded-lg hover:bg-blue-700 items-center gap-2">
<!-- After: prettier-plugin-tailwindcss sorts automatically on save -->
<div class="flex items-center gap-2 rounded-lg bg-blue-600 p-4 text-white hover:bg-blue-700">The official prettier-plugin-tailwindcss plugin reorders classes into a consistent sequence (layout, then box model, then typography, then color, then state variants) every time you save. The specific order doesn't matter much — what matters is that it's the same order everywhere, so a class list looks familiar at a glance instead of forcing you to read every token to find the one you're looking for. Install it once per project and never think about class order again.
Don't let class lists grow unreadably long
<!-- Hard to scan, hides the structure of the component -->
<div class="flex flex-col md:flex-row items-start md:items-center justify-between gap-4 rounded-xl border border-slate-200 bg-white p-6 shadow-sm hover:shadow-md transition-shadow dark:border-slate-700 dark:bg-slate-800">There's no hard line for "too long," but once a class string stops fitting on one line comfortably, it's usually a sign the element itself is doing too much and should be split into smaller pieces — a wrapper component plus a couple of children — rather than a signal to keep the one giant class string and just scroll horizontally past it.
Common mistakes
- Fighting specificity with
!important. Reaching for!bg-red-500to force an override usually means two utilities are competing that shouldn't both apply — the real fix is almost always to remove the losing class rather than force the winner. - Rebuilding
@apply-based component classes everywhere. As covered in an earlier lesson, this reintroduces the naming and indirection problem utilities were meant to remove — prefer extracting an actual framework component. - Forgetting mobile-first ordering. A stray
lg:flexwith no unprefixed base class doesn't mean "flex on large screens only" — it means the defaultdisplayapplies belowlg, which is rarely intended (see the responsive design lesson). - Hardcoding one-off colors instead of using the theme. A scattered
bg-[#f4f4f5]that happens to be nearly identical tobg-zinc-100fragments the palette for no real benefit — arbitrary values are for genuine exceptions, not routine styling. - Not purging unused custom CSS. Utilities are automatically only-what's-used, but hand-written CSS alongside them (old component classes from a migration, for instance) doesn't get that benefit automatically and can quietly accumulate dead weight.
A short mental checklist
Before shipping a component, it's worth asking: does this class list read top-to-bottom as "layout, then spacing, then appearance, then state"? Is every color and spacing value coming from the shared scale rather than an arbitrary one-off? And if this exact combination of classes appears in more than one place, has it been extracted into a component yet? Utility-first CSS scales well precisely because these small habits keep the "utility" classes from turning into an unreadable pile — the framework does the hard part, and consistency does the rest.