There is a button in a post by Andy Robinson that I keep thinking about. Its className is long enough to wrap three times on a normal screen — padding, background, hover state, focus ring, rounded corners, transition, the works — and somewhere in the middle of all that, if you squint, there is the word "Save." His line for it is the cleanest version of the whole anti-Tailwind argument I have read: the HTML "is no longer a document; it's a stylesheet written in the wrong place." His post is titled, with appropriate fatigue, "I Don't Like Tailwind. Sorry, Not Sorry."
I want to do something the Tailwind argument almost never gets: take it seriously instead of taking a side. This blog runs Tailwind v4. That should make me the defendant, not the judge — so let me try to be fair by steelmanning the case against the tool I use every day, and then being honest about which parts of that case actually hold.
The part that is real
Start with the strongest version, the one Robinson nails: utility soup buries the semantic signal. When every element carries a dozen presentational classes, the markup stops reading as a structure and starts reading as styling that wandered into the wrong file. You lose the thing HTML was good at — being a legible description of what this is — and you get back a flat list of how this looks. That is not a taste complaint. It is a real cost to the one job markup has, and no amount of "you get used to it" makes the signal-to-noise ratio better. You do get used to it. The noise is still there.
The second argument is the most concrete, and the one I think critics under-press rather than over-press: coupling. A mature codebase ends up with tens of thousands of class strings, and every one of them is written against a single tool's particular API — its spacing scale, its breakpoint prefixes, its hover: and group-* and arbitrary-value brackets. That is lock-in, plain and measurable. Plain CSS does not have a vendor. padding: 1rem will mean the same thing in 2040. p-4 means whatever Tailwind decides it means, and migrating off it is not a find-and-replace — it is a rewrite of your entire presentation layer. When people wave this away as "every dependency is lock-in," they are dodging a difference of degree so large it becomes a difference of kind. Most dependencies live behind an interface. Tailwind lives in your markup, on every element, by design.
The third argument — skill atrophy — is true but mislabeled. The claim is that if you always translate design intent into utility classes, you never build the intuition for writing CSS directly. I think the mechanism is real: a tool that makes the easy 90% frictionless does let the underlying skill go soft, the same way a good ORM can leave a team unable to read a query plan. But this is a property of how a team uses a tool, not a property of the tool. "Our juniors never learned CSS" is a training problem with a Tailwind-shaped symptom. You can run Tailwind and still expect people to know why flex does what it does. Whether you do is a choice your team makes, and blaming the framework for that choice is letting yourself off the hook.
The part that is just vibes
Now the arguments I think are smuggling aesthetics through the engineering door.
"Every Tailwind project looks the same." Probably true, and almost entirely beside the point. The sameness comes from people shipping the default scale and the most-copied component patterns without editing them — which is a statement about defaults and effort, not about the tool's ceiling. You can build something with a distinct character in Tailwind; most people don't, because most people reach for the path of least resistance in any system. That is human, not technical. And "it doesn't feel like craft" is the purest version of the vibe: it is a claim about how writing the code feels to the author, not about what the output does for the user. Craft is a real value. I care about it. But "this doesn't feel like woodworking" is an aesthetic preference, and dressing it in the language of maintainability does the honest critique a disservice by association. Name it as what it is and it is still a perfectly good reason to prefer hand-written CSS. It is just not a reason it is better.
The counterweight, and the honest question
Here is what even the critics concede, Robinson included: on a large team, a constrained scale and a shared vocabulary solve real consistency problems. Twelve developers who can only choose from a fixed set of spacing values will produce a more coherent interface than twelve developers each free-handing margin: 17px. That is genuine, and it is the reason Tailwind won.
But the concession contains the actual question. A constrained scale and shared conventions are not unique to Tailwind — they are what a design system is. So the honest comparison is never "Tailwind vs. chaos." It is "Tailwind vs. a hand-rolled set of tokens and components that gives you the same constraints without the coupling." Sometimes Tailwind wins that comparison on cost: you get the system for free on day one instead of building and maintaining it. Sometimes it loses it: a long-lived product where the lock-in compounds and the markup legibility matters more than the head start. The answer is per project, and anyone who gives you a universal one is selling a tribe.
The trade-off is older than the tool
The reason this argument never resolves is that it isn't really about Tailwind. It is the same trade-off we have been having forever, just on a new battlefield: convention versus configuration, abstraction versus control, the head start versus the lock-in. Rails had this fight. ORMs had this fight. Every framework that trades some of your control for a lot of your time has had this fight. Tailwind is just the current arena.
And here is the connection I find genuinely funny. Tailwind v4 is itself built on the modern CSS that critics now point to as the reason you could leave it — real @layer cascade layers, @property-registered custom properties, color-mix(). Meanwhile native CSS has, as of 2026, quietly shipped most of what people used to need a tool for. Nesting and cascade layers are Baseline and safe to use today; @scope, the closest native answer to component-scoped styles, only reached Baseline "newly available" status in late 2025 (Firefox shipped it in version 146), so it is real but worth feature-detecting rather than betting the build on. The ground under the entire argument is moving. The abstraction and the platform it abstracts are converging.
So I refuse the binary, and I think that is the only honest place to land. The maintainability critique — buried semantics, real coupling — is legitimate and you should weigh it. The romance-of-craft critique is a preference, and a fine one, but it is not an argument. Separate the two, decide per project, and stop performing the flame war. I run Tailwind here. If this were a product I expected to maintain for fifteen years, I might not. Both of those can be the right call, because they are answers to different questions — and pretending there is one answer is the only position in this whole fight I am actually sure is wrong.