Balázs Barta

Design Technologist

Back

I tried to love TailwindCSS, here's why I couldn't

Balázs Barta ∙ Published on February 11, 2025
I tried to love TailwindCSS, here's why I couldn't

Every few years, our industry falls in love with a trend that promises to revolutionize how we write CSS. Right now, that trend is TailwindCSS. Scroll through tech Twitter or GitHub, and you’ll see developers praising its utility-first approach. But as someone who’s spent years crafting maintainable CSS systems, I see a concerning pattern: we’re returning to practices we fought hard to move away from.

Going back to inline styles (just with extra steps)

Remember when we used to write styles directly in our HTML? When every element had its own style attribute, making global changes meant searching through countless files? TailwindCSS feels strikingly similar. Let’s look at a simple button:

html
<!-- Traditional approach -->
<button class="btn btn-primary">Default</button>

<!-- Tailwind approach -->
<button 
  class="text-white bg-blue-700 hover:bg-blue-800
  focus:ring-4 focus:ring-blue-300 font-medium
  rounded-lg text-sm px-5 py-2.5 me-2 mb-2
  dark:bg-blue-600 dark:hover:bg-blue-700
  focus:outline-none dark:focus:ring-blue-800">
    Default
</button>

The difference is striking. The traditional approach tells you exactly what this element is - a primary button. The Tailwind version? It fundamentally uses inline styles disguised as classes. We’ve replaced ⁠style="background-color: blue" with ⁠bg-blue-700, but the fundamental problem remains: we’re mixing content with presentation.

My journey with CSS

Throughout my career, I’ve worked with various styling approaches. From the early days of inline styles to CSS frameworks like Bootstrap, to modern CSS-in-JS solutions like styled-components. Each step in this evolution taught me something valuable about maintaining large-scale web applications.

When Tailwind gained popularity, I spent time exploring it, understanding its appeal. The promise of never having to write CSS again is tempting. But as I dug deeper, I realized we were sacrificing one of the web’s fundamental principles: the separation of concerns.

The real cost of utility-first CSS

The problems with Tailwind become apparent when your project grows. Want to change how all your primary buttons look? With traditional CSS, it’s one change in your stylesheet. With Tailwind, you’re hunting through your entire codebase, replacing dozens of utility combinations.

And what happens when design requirements change? Imagine updating the padding on all your cards from ⁠p-4 to ⁠p-6. With traditional CSS, it’s a single line change. With Tailwind, it’s a search-and-replace operation that could easily miss edge cases or break other components.

Modern CSS is more powerful than ever

The irony is that we’re adopting these utility frameworks just as CSS itself has become incredibly powerful. Modern CSS features like variables, grid, and logical properties give us everything we need to write maintainable, scalable styles:

CSS
.btn {
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-md);
    font-weight: var(--font-weight-medium);
    transition: var(--transition-smooth);
}

.btn-primary {
    background: var(--color-button-bg-primary-default);
    color: var(--color-button-label-primary-default);
}

This approach isn’t just cleaner - it’s more powerful. We’re not just styling elements; we’re building a design system that’s easy to maintain and update.

The maintenance nightmare

Advocates of Tailwind often argue that it eliminates the need to think about naming conventions. But names serve a purpose - they convey meaning. When I see ⁠.card, I know what it represents. When I see ⁠p-4 rounded-lg shadow-md, I have to mentally parse multiple style definitions just to understand what I’m looking at.

This cognitive overhead becomes a real problem in larger teams and projects. New developers need to learn not just what components exist, but memorize combinations of utility classes that create those components.

Choosing the right tools

I’m not suggesting Tailwind doesn’t have its use cases. For rapid prototyping or small projects, it might be perfect. But for large, maintainable codebases, traditional CSS with a proper methodology is still the better choice.

Modern CSS development isn’t about avoiding CSS - it’s about embracing its power while maintaining clean, semantic HTML. Sometimes that means vanilla CSS with a solid naming convention. Other times it might mean CSS Modules or scoped styles in frameworks like Astro.

Conclusion

The web development community often swings between extremes - from inline styles to utility classes, from global CSS to scoped styles. But the fundamental principles of good web development haven’t changed: separate your concerns, write semantic code, and think about maintainability. As we move forward, I hope we can focus less on following trends and more on understanding these core principles. After all, the code we write isn’t just for browsers to render - it’s for other developers to read, understand, and maintain.