Tailwind looks bad on "paper". It violates a lot of "best practices". It is ugly. Yet in reality it works. It gets the job done. It is fast to work with.
What is funny with your article is that you talk about tradition, when actually these traditions are based on assumptions which are themselves based on beliefs like : "separation of structure and style are a good thing".
But this belief is only true if the language to describe the structure is html or js which creates not reusable pieces of style/structure.
But when you go for a different approach where everything is functions and strong types (ADT), like when you use haskell for exemple, this debate is over, because you handle EVERYTHING in your code, and stop fragmenting the truth into opaque and dissociated worlds (html, js, css, database, glue, docker, ...).
This is such a bikeshedding debate. While you don't recommend it, projects with Tailwind work. Over years. You can onboard new developers to it, able to contribute productively immediately. Likewise, you can pick up work after months or years and don't have to remember or rediscover how your styling layer works.
The conventions and class names come really naturally fast, and you can always look it up. It's just not as a big of a problem people make it.
But the most ridiculous part of the article I found the cascade complaint:
<p class="text-red-500 text-green-500">I am some text</p>
Yes, this does not work. Why should it?! There is not a single use case where this is a good idea! In classic CSS, you might want to override something based on modifier classes, but that is just not a thing with Tailwind! If you end up programmatically layering class names, you're looking at a code smell. Instead, you want to use attribute or state modifiers, like `aria-hidden:opacity-0`.
I can see this argument both ways. On the one hand, you'd expect the last assignment to take precedence. This works perfectly well with the style attribute, and this is how variable assignment works in procedural programming. On the other, it doesn't make sense to have two conflicting styles. In programming languages, this might be akin to raising an exception or UB.
The random outcome, entirely dependent on the Tailwind generation internals, is the worst of all worlds though, it's just an unfortunate side-effect of relying on cascading sheets to drive atomic styles. I say this as someone who exclusively uses Tailwind.
Saying "unless you use @apply" invalidates this article for me. Everyone knows that @apply only exists as an escape hatch, it is not supposed to be used, except for when it's necessary like for compatibility with libraries that declare their own classes that you need to override.
The most commonly repeated point in the article is "escape hatches bad" and I think that's completely absurd. Of course you want escape hatches, otherwise when you do hit an edgecase you get stuck with no solution. That's exactly what would force you to throw away that approach and pivot. Tailwind doesn't have that problem because it was designed to include escape hatches.
Users deciding to use those escape hatches instead of sticking to a design, isn't Tailwind's fault.
I'm not a frontend guy so take this with a pinch of salt, but for a few personal projects I've done my approach is now "ai pls generate css". I thought it would be inconsistent and broken, but if you tell it to care about accessibility and you're willing to clean up a bit it's not that bad and you end up with very compact transfers after minification.
I tend to like simpler/textual interfaces though, admittedly this won't be everyone's cup of tea.
God help me, somewhere around 2016 I started using some alpha version of Bootstrap 4, and I just keep using that same version for all the basic stuff underneath my own SCSS for whatever I'm building. It's absolutely fine. A lot of it is displaced now by grids, but for flexbox stuff and modals and pushing rows and columns it just works. Very easy to remember class names and extend it. Thankfully I don't work for a company that cares about using the latest thing.
The only really critical things I need in scss are scaling typography and variables representing colors for iteratively generating class names and gradients and transparencies and stuff like that. By "scaling typography" I mean, I just have a loop that writes .scaling-typography-[a]-[b] where a and b range from 1 to 16, and the class that's generated scales from [a]em to [b]em between a phone size and a desktop size. In a rare case where that doesn't just work or it doesn't look good on a tablet or something, a couple specific rules extending xs- or sm- or whatever will cover it.
I’d be rather interested in a recommandation that don’t comes with de usuals pits of others solutions and comes with a the actual css code that will apply to the element displayed in autocomplete while editing the html / jsx.
I've used a lot of tailwind professionally over the last few years and I agree with this article - it is spot on.
I never even use tailwind in my own stuff, even though I think that small devoper-led side-projects are where it is a good fit (and the reason for it's popularity).
I can immediately spot organizations void of any skilled frontend engineering leadership by their use of Tailwind.
Generally coupled by some memory leaking React soup, solving 2016 problems in 2026.
Likely 30-something years old MIT-bred leetcode ninjas that know little to nothing about front end technologies in the first place.
Bloated slop is bloated slop, I still have to find a single example proving me wrong, and what's produced on top of react-tailwing by billion dollar companies just confirms my negative bias.
My sass customers don't even know what css means, it's fine. Nobody cares as long as the things they expect are on the page in the right position and font is readable.
As a 26+ year frontender, years ago I was against it on so many levels. Until I tried it.
Never looked back. Also, inheriting projects with someone else’s code is fine. Just a quick look at the central config and you’re good to go.
100% this. It looks terrible until you try it and it starts making so much sense.
Also works great with agent assisted development.
Tailwind looks bad on "paper". It violates a lot of "best practices". It is ugly. Yet in reality it works. It gets the job done. It is fast to work with.
Constraints are known to enhance creativity.
What is funny with your article is that you talk about tradition, when actually these traditions are based on assumptions which are themselves based on beliefs like : "separation of structure and style are a good thing".
But this belief is only true if the language to describe the structure is html or js which creates not reusable pieces of style/structure.
But when you go for a different approach where everything is functions and strong types (ADT), like when you use haskell for exemple, this debate is over, because you handle EVERYTHING in your code, and stop fragmenting the truth into opaque and dissociated worlds (html, js, css, database, glue, docker, ...).
This is such a bikeshedding debate. While you don't recommend it, projects with Tailwind work. Over years. You can onboard new developers to it, able to contribute productively immediately. Likewise, you can pick up work after months or years and don't have to remember or rediscover how your styling layer works.
The conventions and class names come really naturally fast, and you can always look it up. It's just not as a big of a problem people make it.
But the most ridiculous part of the article I found the cascade complaint:
Yes, this does not work. Why should it?! There is not a single use case where this is a good idea! In classic CSS, you might want to override something based on modifier classes, but that is just not a thing with Tailwind! If you end up programmatically layering class names, you're looking at a code smell. Instead, you want to use attribute or state modifiers, like `aria-hidden:opacity-0`.I can see this argument both ways. On the one hand, you'd expect the last assignment to take precedence. This works perfectly well with the style attribute, and this is how variable assignment works in procedural programming. On the other, it doesn't make sense to have two conflicting styles. In programming languages, this might be akin to raising an exception or UB.
The random outcome, entirely dependent on the Tailwind generation internals, is the worst of all worlds though, it's just an unfortunate side-effect of relying on cascading sheets to drive atomic styles. I say this as someone who exclusively uses Tailwind.
> […] You can onboard new developers to it, able to contribute productively immediately […]
In the era of AI, it does not matter anymore.
Anyone can simply ask their Agent CLI to resume work from any code base, regardless of their familiarity with the underlying technologies.
Saying "unless you use @apply" invalidates this article for me. Everyone knows that @apply only exists as an escape hatch, it is not supposed to be used, except for when it's necessary like for compatibility with libraries that declare their own classes that you need to override.
The most commonly repeated point in the article is "escape hatches bad" and I think that's completely absurd. Of course you want escape hatches, otherwise when you do hit an edgecase you get stuck with no solution. That's exactly what would force you to throw away that approach and pivot. Tailwind doesn't have that problem because it was designed to include escape hatches.
Users deciding to use those escape hatches instead of sticking to a design, isn't Tailwind's fault.
Tailwind is great. Not sure why you'd use anything else at this point.
I'm not a frontend guy so take this with a pinch of salt, but for a few personal projects I've done my approach is now "ai pls generate css". I thought it would be inconsistent and broken, but if you tell it to care about accessibility and you're willing to clean up a bit it's not that bad and you end up with very compact transfers after minification.
I tend to like simpler/textual interfaces though, admittedly this won't be everyone's cup of tea.
God help me, somewhere around 2016 I started using some alpha version of Bootstrap 4, and I just keep using that same version for all the basic stuff underneath my own SCSS for whatever I'm building. It's absolutely fine. A lot of it is displaced now by grids, but for flexbox stuff and modals and pushing rows and columns it just works. Very easy to remember class names and extend it. Thankfully I don't work for a company that cares about using the latest thing.
The only really critical things I need in scss are scaling typography and variables representing colors for iteratively generating class names and gradients and transparencies and stuff like that. By "scaling typography" I mean, I just have a loop that writes .scaling-typography-[a]-[b] where a and b range from 1 to 16, and the class that's generated scales from [a]em to [b]em between a phone size and a desktop size. In a rare case where that doesn't just work or it doesn't look good on a tablet or something, a couple specific rules extending xs- or sm- or whatever will cover it.
> there is a ceiling of basic classes you have to internalize
I think you mean floor. Floor is a minimum you need. Ceiling would be the maximum you can achieve.
Below this floor you're not useful. There's a ceiling to how much you can do with no code tools.
I've seen one of these posts every 6 months for the last 5 years and not a single one has figured out components yet.
I agree with all points and they are the reason I'm very selective which project uses it and which doesn't.
It did give me some ideas for my own stylesheet writing though. The colorsystem is something even non-tailwind projects will have now.
The problem isn’t tailwind, it’s css.
It always has been css.
That being said, it’s a hard problem and I don’t have a better idea.
Tailwind seems to at least fix or move the problem in the right direction.
Counterpoint: the problem is actually HTML and most of webtech is increasingly elaborate cope mechanisms to deal with the original sin.
I think tailwind helps. It is same as AI prompting, but in a deterministic and fine-grained way. Bottom line - it reduces the time to build.
I’d be rather interested in a recommandation that don’t comes with de usuals pits of others solutions and comes with a the actual css code that will apply to the element displayed in autocomplete while editing the html / jsx.
I've used a lot of tailwind professionally over the last few years and I agree with this article - it is spot on.
I never even use tailwind in my own stuff, even though I think that small devoper-led side-projects are where it is a good fit (and the reason for it's popularity).
I wish it would at least be kept out of UI frameworks.
I can immediately spot organizations void of any skilled frontend engineering leadership by their use of Tailwind.
Generally coupled by some memory leaking React soup, solving 2016 problems in 2026.
Likely 30-something years old MIT-bred leetcode ninjas that know little to nothing about front end technologies in the first place.
Bloated slop is bloated slop, I still have to find a single example proving me wrong, and what's produced on top of react-tailwing by billion dollar companies just confirms my negative bias.
My sass customers don't even know what css means, it's fine. Nobody cares as long as the things they expect are on the page in the right position and font is readable.
Nobody does. Yet it is everywhere, like AI slop.