Your HTML Looks Like Garbage
Let's be honest: class=\"flex items-center justify-between py-2 px-4 bg-gray-100 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500 active:bg-gray-300 disabled:opacity-50 disabled:cursor-not-allowed\"
is not readable code.
When you're debugging at 2am and need to figure out why a button is broken, good fucking luck parsing that class nightmare. Your designer asks for one small change and you're hunting through 15 utility classes like you're debugging regex. I've seen developers spend 30 minutes hunting through utility classes to change one button style - time that could've been spent on actual features instead of wrestling with CSS architecture.
Build Times That Kill Your Flow
Tailwind's JIT compilation is "fast" until you have a real application. Hit 500+ components with complex design tokens and watch your build time creep from 2 seconds to 15 seconds. Every hot reload becomes a coffee break.
I've seen teams where developers avoid making CSS changes because the feedback loop is too slow. That's a broken workflow that kills productivity. JIT helps but doesn't solve the real problem when you're dealing with large codebases that have thousands of utility combinations. The PostCSS processing gets slow as hell when you throw thousands of utility combinations at it.
Your Design System Fights Back
Try implementing a proper design system with Tailwind and you'll understand the pain. Need consistent spacing that isn't 4px
increments? Fight with the config. Want proper color variants that aren't gray-100
to gray-900
? More config fighting.
Design systems need tokens that don't fight you every step of the way. Tailwind gives you rigid utilities that work great for prototypes but become constraints in production. When you need actual design system flexibility - not just predefined color ramps - you end up fighting the framework instead of building features. Ever tried implementing a consistent design token system with Tailwind? You'll spend more time in tailwind.config.js
than writing components.
The Bundle Size Reality Check
"But it purges unused CSS!" Sure, until you have dynamic classes. Or third-party components. Or you import one library that uses string concatenation for class names. Suddenly your "optimized" CSS bundle is 150KB because the purger missed half your classes.
I've debugged this nightmare on production sites where PurgeCSS failed silently and users got broken layouts. Real horror story: E-commerce site using React + Tailwind, dynamic class names like ${'text-' + variant + '-500'}
got purged in production. Half the product cards had no colors. Customer complaints poured in. Took 6 hours to figure out the purge config was too aggressive. Always safelist your dynamic classes or you'll get fucked.
When Tailwind Actually Works
Don't get me wrong - Tailwind isn't always the wrong choice:
- Rapid prototyping: Nothing beats it for throwing together a quick interface
- Small teams without design systems: The defaults are solid
- Static sites with simple interactions: Perfect use case
But if you're building a complex application with multiple developers, established design patterns, and performance requirements, there are better options. The trick is knowing when to jump ship before you're too deep in utility class hell.