Technical
Tailwind at Four Months: What Still Frustrates Me
Tailwind is my default CSS approach. I have written enough about why it wins. But no tool is perfect and I have accumulated a list of real frustrations over four months of daily use. Airing them here in case you are weighing the trade-off yourself.
Class Strings Grow Long
A simple button can have 12 utility classes. A responsive grid item can have 20. Reading JSX in a large component becomes an exercise in scanning for the element you care about between walls of class names. No amount of extraction hides this entirely.
Mitigations exist. The @apply directive in CSS. Component extraction in React or Vue. But these undo some of the benefits of Tailwind, which was keeping styles next to markup. You pick your trade-off.
Arbitrary Values Are a Trap
Tailwind lets you escape the design system with arbitrary values like text-[#ff1234] or mt-[23px]. This is useful for one-off cases. It is poison for consistency. Once a codebase has 40 arbitrary values scattered around, you have lost the spacing and color systems that Tailwind was supposed to provide.
I now lint against arbitrary values in CI. Exceptions require a code review. This rule alone has kept design drift out of three different projects this year.
Theming Is Verbose
Dark mode requires prefixing half your classes with dark:. Custom color palettes require tailwind.config.js entries plus actual usage. A design system with five themes becomes a lot of duplicate class names and careful coordination.
// Dark mode requires dual classes everywhere
<div className="bg-white text-gray-900 dark:bg-gray-900 dark:text-white">
<h2 className="border-b border-gray-200 dark:border-gray-700">...</h2>
</div>CSS variables solve this more elegantly. Tailwind 4 is improving here but the 3.x ergonomics are not pleasant.
IDE Support Is Not Perfect
IntelliSense is good but not complete. Dynamic class names like bg-${color}-500 defeat it. You lose autocomplete and the JIT compiler may miss the class entirely. The workaround is to use a class lookup object, but it is friction.
The Honest Verdict
I still use Tailwind on everything new because the benefits outweigh the frustrations. But the frustrations are real and growing. Tailwind 4 addresses some. Others are inherent to utility-first CSS.
See the Tailwind documentation for the official perspective. The honest user perspective includes the frictions, because knowing them upfront helps you decide if the trade-off fits your project.
RELATED READING
The Consulting Shift I Am Making In Year Two
After a year of writing and building, my consulting practice is changing shape. Shorter engagements. Sharper outcomes.
ReadThe Frontend Shift: Shipping Less JavaScript In Year Two
A year ago I reached for Next.js for everything. This year I often reach for nothing.
ReadThe Serverless Lesson I Would Write On A Sticky Note
After a year of shipping serverless projects, one rule explains most of the wins and all of the losses.
Read