www.spicyweb.dev
Why Tailwind Isn't for Me
Excerpt
### Reason 1: Tailwind promotes ugly-ass HTML. # This first reason is an aesthetic concern, yet it’s intimately related to real technical challenges which I’ll outline shortly. But at the very least, I **hate** the way utility-css-only HTML looks. Hate, hate, hate it. Adam even acknowledges this head on when he begs us to “suppress the urge to retch long enough to give it a chance…”. This is a tacit admission that writing markup this way initially seems ugly and weird—but somehow we’ll eventually just “get over it” because the benefits are so great. … ### Reason 2: `@apply` is fundamentally incompatible and non-standard (and largely unnecessary). # This is where a lot of Tailwind fans get tripped up and keep on arguing with me over and over again, so I’ll try to explain this as clearly and obviously as possible. `@apply mt-3`in a CSS file *only*works if you use Tailwind. It requires the presence of Tailwind in your build process. If you remove Tailwind from your build process, that statement doesn’t work and your CSS is broken. - While it’s true you can take the generated output CSS of a site and use that without Tailwind, it’s typically a bundled compilation of dozens if not hundreds of small CSS files scattered around a codebase (if you write CSS-per-component files like we do). It’s not something you can count on for source code. - Therefore, it’s simply the truth that CSS files built for Tailwind are non-standard (aka proprietary) and **fundamentally incompatible**with all other CSS frameworks and tooling. Once you go Tailwind, *you can never leave*. (da da dum 😱) - And as an added bonus, writing all your CSS files with … And while `@apply` seems cool on the face of it, it ends up becoming an enormous crutch. For example, I like the way Tailwind makes writing styles using CSS Grid techniques pretty straightforward. Unfortunately, after having done so, I still don’t really understand Grid syntax itself. I remain ignorant of the open CSS standard. As for why `@apply` in the grand scheme of things is largely unnecessary, that brings me to my third point. ### Reason 3: Tailwind’s focus on design systems and tokens could mostly be replaced by CSS Custom Properties (aka variables)—which IS a standard. # People initially like Tailwind because it comes out-of-the-box with a nice design system and lots of tokens you can tweak (colors, font sizes, spacing, etc.). It’s easy to get good-looking results quickly. … *native* to all modern browsers. Speaking of what’s native in modern web browsers… ### Reason 4: Tailwind forgets that web components exist. # This is perhaps the biggest knock against Tailwind. It seemingly was conceived and promoted in a world where web components don’t exist. Tailwind CSS is completely unusable within the Shadow DOM. Some enterprising developers have come up with solutions where select bits of Tailwind styling can get injected into components through a build process, but it’s definitely a hack. … ### Reason 5: Finally, Tailwind encourages div/span-tag soup. # I almost included this in the previous point, but it really bears its own conversation. I have become convinced by now that using `<div>` and `<span>` tags everywhere in your markup is an anti-pattern. We live in a world where custom elements (aka … **looks amazing** and works quite well—all without needing *any* of the many megabytes of Tailwind utility classes that you then need to purge to get your performance back down to manageable levels. In other words, Tailwind’s main selling point (besides rapid prototyping via utility classes) is its attractive design system—yet the way it implements that design system really kind of sucks! (Incompatible with web components by default, only minimally leverages CSS variables, doesn’t encourage custom elements/attributes with relevant scoped styling…)
Related Pain Points
Incompatibility with Web Components and Shadow DOM
7Tailwind CSS is completely unusable within the Shadow DOM, making it fundamentally incompatible with Web Components. While workarounds exist via build-process injection, they are acknowledged as hacks and not a native solution.
Vendor lock-in due to non-standard CSS syntax
7Tailwind's `@apply` directive only works within Tailwind and is not part of the CSS standard. CSS files written for Tailwind are fundamentally incompatible with other CSS frameworks and tooling, creating a one-way dependency that prevents migration.
Loss of fundamental CSS knowledge among developers
6Developers using Tailwind are abstracting away core CSS knowledge (Flexbox, Grid, positioning). Junior developers can use Tailwind classes but don't understand the underlying CSS properties, creating a generation gap in web platform fundamentals.
Encourages semantic HTML anti-patterns with div soup
5Tailwind's utility-class approach promotes overuse of generic `<div>` and `<span>` tags instead of semantic HTML elements, leading to less accessible and maintainable markup that doesn't leverage modern custom elements.
Custom CSS implementation in Tailwind projects negates framework benefits
5Complex projects require custom CSS alongside Tailwind utilities and @apply overrides, creating a hybrid CSS architecture. This defeats the purpose of using Tailwind and introduces maintenance complexity from multiple paradigms coexisting.
Separation of concerns violated by mixing styles with markup
3Tailwind mixes CSS styling concerns directly into HTML markup, violating traditional separation of concerns principles and resulting in code that looks like inline styles, which many developers find aesthetically unpleasant.