Moving away from Tailwind, and learning to structure my CSS
jvns.ca
jvns.ca
I've been teaching semantic HTML / accessible markup for a long time, and have worked extensively on sites and apps designed for screen readers.
The biggest problem with Tailwind is that it inverts the order that you should be thinking about HTML and CSS.
HTML is marking up the meaning of the document. You should start there. Then style with CSS. If you need extra elements for styling at that point, you might use a div or span (but you should ask yourself if there's something better first).
Tailwind instead pushes the dev into a CSS-first approach. You think about the Tailwind classes you want, and then throw yet-another-div into the DOM just to have an element to hang your classes on.
Tailwind makes you worse as a web developer from a skill standpoint, since part of your skill should be to produce future-proof readable HTML and CSS that it usable by all users and generally matches the HTML and CSS specs. But devs haven't cared about that for years, so it makes sense that Tailwind got so popular. It solved the "I'm building React components" approach to HTML and CSS authoring and codified div soup as a desirable outcome.
Tailwind clearly never cared about any of this. The opening example on Tailwind's website is nothing but divs and spans. It's proven to be a terrible education for new developers, and has contributed to the div soup that LLMs will output unless nudged and begged to do otherwise.
can tailwind be used poorly? absolutely. but that's true of any tool
i've been writing CSS for ~20 years and am quite capable with it, having used CSS, Less, SASS/SCSS, Stylus, PostCSS etc. the reason i have settled on Tailwind for the last few years is precisely because it enables me to build more robust application styling.
tailwind frees you from having to spend excessive time building abstractions of styles/classes that will invariably change. placing the styles directly into the markup that is affected by it reduces cognitive load, prevents excessively loose selectors affecting styles unintentionally and really aids in debugging. jumping into codebases with bespoke css frameworks is always more complex and fragile than a tailwind codebase for anything but the most simple sites/apps
add to that the ability to have consistent type, color and sizing scales, reduced bundle sizes, consistency for any developer who knows tailwind and a very robust ecosystem (and thus llms are very familiar with it) and tailwind is a really excellent choice for a lot of teams
tailwind is like most tools; it can be used well or poorly depending on who is using it
Abstractions like a hero image, a menu, a headline? Sure, it's easy to overthink things but most of the time, it's not that complex.
> placing the styles directly into the markup that is affected by it reduces cognitive load, prevents excessively loose selectors
In my opinion, it's the opposite. Besides the obvious violation of DRY and the separation of concerns, inline CSS can't be cached and it creates a lot of noise when using dev tools for debugging. It actually increases cognitive load because you have to account for CSS in two different locations.
Lots of people use Tailwind because they don't want to deal with the cascade, usually because they never learned it properly. Sure, back in the day, the web platform didn't provide much built-in support for addressing side effects of the cascade, but now we have @layer and @scope to control the cascade.
Tailwind uses a remnant of '90s web development (inline CSS) and built an entire framework around it. I get why it appeals to some people: it lets you use CSS while not requiring an understanding of how CSS works, beyond its most basic concepts.
> inline CSS can't be cached
this shows your lack of understanding. first off, it's not inline css, they're classes and thus you only ever define "flex" in one place vs many many places in non-utility css approaches. in fact, sorted html classes are compressible over the wire so you're doubly wrong.
> because they never learned it properly condescending
> it lets you use CSS while not requiring an understanding of how CSS works, beyond its most basic concepts also condescending and just such a boring, over used argument i always hear from haters of tailwind maybe try and counter my arguments without the attitude? maybe understand seasoned veterans of css might have their reasons to choose it?
Sure it’s not as dry, but I’ve been bitten in this regard because css framework and templates are so intransparent, preventing me from simply changing padding or margin.
CSS is too detailed and too verbose. Frameworks like bootstrap are too high level and don’t give enough control. Tailwind hits the sweet spot whilst allowing me to be detailed if I want to. It allows me to just get it done.
Can vanilla CSS be used for a complex app? Yes. But, it takes discipline, and I only have a limited amount of that. I’d rather spend my discipline budget on other things.
That said, nested selectors and CSS variables have gone a long way towards making the vanilla experience much more pleasant. I may have to give it a shot on a side project one of these days.
If CSS had nesting, variables, media queries, the other nice selector queries like :has, and modules out of the gate, we likely would have not needed much of the tooling like tailwind that eventually got built to manage it all with less boilerplate. We built the tools because even when these features rolled out they came in fits and starts so you couldn’t adopt it without polyfills and whatnot.
Can you elaborate what the problem is? What is it you want to cache?
> and it creates a lot of noise when using dev tools for debugging.
I don’t think so. The element styles have an own section (assuming you debug the applied styles)
> It actually increases cognitive load because you have to account for CSS in two different locations.
Same applies to no tailwind. You need to account for the html (is parent block / inline / …) anyway.
Also, DRY can still be somewhat achieved with tailwind by using reusable components, in whatever framework you're using. It could be React, but it could even be blade components in a traditional SSR Laravel app.
Many times it's fine to repeat yourself. Many times it's fine for a component to cross multiple concerns.
How does doing everything in-line (one place) cause two locations?
Thanks.
Classes are now in-line styling? Why are you doubling down on a subject you're obviously not familiar with?
And the separation of concerns argument is always strange to me because in React, my concern is the component.
Please show me only ten of the SaaS you lead that rely on your CSS framework.
You must have one, because you talk about structure and premises. Orderly put and repeatedly applied you get a framework.
I doubt it.
I registered my first domain 1997. I love to debate anyone coming up with a clever not so clever theoretical argument against Tailwind.
Where are all the you might not need jQuery JavaScript guys?
The same goes for Tailwind.
And just as a reminder: CSS started as so called separation of markup and design. A zen garden tried to proof this but only showed how one cannot exist without the other.
Loose coupling as the saying goes.
Since the ACID test CSS went from some proposals to a stunning black hole of finally receiving differential treatment with the level nomenclature.
And you besides all incompatibility issues and different browsers still think that you really grasp CSS or even know how to apply it semantically correct even though by matter of fact many concepts feature bogus terminology due to compatibility issues?
I would love to interview you regarding edge cases. Do you get box models? Collapsing markings? Floats? Clearfix? Order of application?
Print layouts? Views vs fluid design?
Really, attacking Tailwind is the same as “Let’s build our own Google” trope. It shows lack of competence.
There is such a thing as the ergonomics of the tool. Yes div soup has been around a long time. But also yes, Tailwind makes the wrong approach the easy one.
It’s ergonomics encourage adding div elements to support styles. It’s the core design loop.
You’re conflating “forces to” and “ergonomically encouraged”.
The ergonomics in my day to day work are quite nice. To me, the better boundary of abstraction shifted to components, rather than the html/css/js “separation of concerns” that some of the older folks still like to parrot.
However, take a look at the markup and styling for the https://maps.apple.com/ web property.
I can’t deny that it’s quite beautiful and easy to holistically understand. Especially when it comes to the responsive styling—which is when I tend to find tailwind most awkward.
It’s my favorite example of “traditional” CSS structure in recent memory that has given me some pause when it comes to Tailwind.
In my mind it’s the best of both worlds. Vue makes it easy. I think CSS modules in React work similarly
Can tailwind be a useful CSS framework? Absolutely, but that can be said of any of them.
Which is precisely why it makes sense to point out it's unique flaws, so that people can make an informed decision as to what works best for them.
If you have some unique feature to tailwind that you think makes it better than the rest, you should share that.
Everything you have listed is also accomplished by all the other CSS frameworks, so it almost sounds like tailwind is simply the main one you have experience with.
But this isn't a unique flaw for Tailwind. I've been coding with CSS since the late '90s and seen plenty of people throw yet-another-div onto the DOM just to have an element to hang their classes on. Done so myself plenty of times, too.
People have been complaining about div soup for years and years before Tailwind ever came along.
Plus I'm coding with Tailwind now, and almost never think about my classes before my HTML. Nothing about Tailwind in particular encourages you to do so. So I'm quite confused how this is a unique Tailwind flaw.
> If you have some unique feature to tailwind that you think makes it better than the rest, you should share that.
i did mention some but you'll then claim it's not unique because some other tool has it so...
> Everything you have listed is also accomplished by all the other CSS frameworks
not true. most frameworks for example do not have nearly the universal familiarity tailwind has, for example. tailwind has a build tool that strips unused selectors and can dynamically build new classes (eg "w-[20rem]") if needed. do all frameworks do that? maybe a few but most do not
> sounds like tailwind is simply the main one you have experience with.
i've used so many frameworks i cannot count them on my hands (and feet even). i've settled on tailwind because it solves problems better than any other tool i've used. that's my preference yes, but your implication that i'm just using it because it's the only thing i know is so far from the truth it's comical
do yourself a favor and stop assuming people choosing tailwind don't know what they're doing
> If you need extra elements for styling at that point, you might use a div or span (but you should ask yourself if there's something better first).
This is IMO not worse than vanilla CSS, and it's simply the only way to have customizable layouting in HTML.
https://en.wikipedia.org/wiki/The_purpose_of_a_system_is_wha...
So what if it does not "force" you?
Hmm. Your reply refutes the div-soup accusation, but doesn’t provide any explanation.
I have a bias against Tailwind, admittedly because I saw some vibecoded Tailwind where each class was essentially equivalent to style="font-size: 4em; background-color: grey; display: flex;", all of which was repeated for each header.
But that could be my bias; perhaps the right way to use is is DRY.
But if you have to use `display: flex" in a lot of places, having the `flex` utility is better. And there are tons of such utilities with Tailwind.
I think herein lies at least part of the problem of the web these days: Most websites don't need to be applications, and are needlessly made to be applications, often even SPAs instead of simply being mostly informational pages, in turn putting different requirements for styling onto the project.
> [...] jumping into codebases with bespoke css frameworks is always more complex and fragile than a tailwind codebase for anything but the most simple sites/apps
There is no need for frameworks. Well structured and scoped CSS can handle it all.
> add to that the ability to have consistent type, color and sizing scales, reduced bundle sizes, consistency for any developer who knows tailwind
What if not that does CSS already offer? I don't see how normal CSS does not already do that. No additional thingamabob needed.
> very robust ecosystem (and thus llms are very familiar with it) and tailwind is a really excellent choice for a lot of teams
Tons of ready-made stylesheets out there to use for teams. What more of an "ecosystem" do I need to style a web page? Why do I need an ecosystem? Is it not rather a tailwind self-induced need?
you read a lot into me choosing "application" instead of using "website". for the record i think tailwind works great for both and it actively using in in a many tens of thousands of LOC web "application" and managing a team using it on a fortune 100 mostly static website that gets millions of views a month.
tailwind works great for both and in fact i'd argue works even better on "static" sites because it's efficient bundles and selector compression over the wire. we don't ship a single byte of css we don't use, thus saving on wasted bandwidth and increasing our SEO/page speeds
> There is no need for frameworks. Well structured and scoped CSS can handle it all.
i love when people are so confident other people don't have valid reasons to use tools. real "junior dev" vibes, my friend
> What if not that does CSS already offer? I don't see how normal CSS does not already do that. No additional thingamabob needed.
how many "bespoke" css projects have you worked on? i've works on MANY. nearly all of them suck to get familiar with and to not risk messing up some weird selector hierarchy you weren't aware of. can it be done well? sure, but it's incredibly rare and often only happens on smaller teams/projects. scaling out bespoke css sites becomes increasingly challenging as you scale in LoC and team size.
on the other hand, give me any tailwind project and i can start contributing immediately
> Tons of ready-made stylesheets out there to use for teams. What more of an "ecosystem" do I need to style a web page? Why do I need an ecosystem? Is it not rather a tailwind self-induced need?
ready-made stylesheets? do you mean like a css/html template?
the ecosystem means IDEs work well with it, there are lots of help resources, llms are trained on them heavily, you can find devs who know how to be productive with it, etc.
you can be very familiar with css but struggle within some bespoke framework with the fact that you can structure css in near infinite ways. tailwind gives you a consistent structure and approach across projects
Totally agree. I feel like this was more a by product of React. Not that React forced this either, but it felt like the rise in both went hand in hand for some reason.
While I think it's true that none of the current top FE technologies force the div soup, they don't discourage it either. It would be nice if what ever FE technologies catch on next did try to encourage better practices around things like accessibility. Make the path of least semantic HTML the path of least resistance and allow people to fall into the pit of success, ya know?
That's never been a valid argument to dismiss criticism. It wasn't with Dreamweaver, any it wasn't with visual basic, and it isn't with Tailwind.
Patterns matter. Best practices matter. Path of least resistance matters. Those are all choices you make when you develop a CSS framework. Some of those choices are good and some are bad.
If none of those things mattered, them choosing a CSS framework would not matter at all.
They fixed this later with Fragments but the damage was done.
<div class="flex flex-col items-center p-7 rounded-2xl">...</div>
The problem with tailwind is that semantic HTML should be entirely free of styling decisions in the ideal case. That also goes for styling classes like flex flex-col etc.The way I would do it is to give the HTML some semantic meaning:
<section class="info-for-nerds">...</section>
We can then decide how to treat section.info-for-nerds. Someone who reads the HTML immediately knows that this section is the bit that gives slightly too much information for nerds. That is what semantic means. The class adds meaning in a semantic sense, that helps to interpret the purpose of the element.Then in CSS you would just style the semantic.info-for-nerds text fully with flex, flex-col, the whole shabang. If there are other info boxes that share style adding a general info-box class is probably a good idea. Again, this is semantic. I don't say red-box. I say what the box is intended to mean, not how it looks.
If you need the Infobox to look different in another context (or want to be sure your selector doesn't leak) you use the cascading bit of the language;
.page-article>article>section.info-for-nerds { ... }
.page-catalog>section.summary>section.info-for-nerds { ... }
Notice btw. that I also prefer to use semantic HTML elements like section, article, main, aside over generic ones like div. Using these well may even mean you don't need any classes at all. If you have three nested divs classes are the only way to k ow which one is the article. If you have main containing article containing section, that may literally be all the info you need.+1
I look at the royal mess that is HTML/CSS/JS as a necessary evil, required when we want to target browsers. To me it's "just the presentation layer".
In my work I put a lot more emphasis on correctness in the db schema, or business logic in the backend.
When it comes to the messy presentation layer I prefer to write a little as possible, while still ending up with somewhat maintainable code. And for this Tailwind fits the bill really well: LLMs write it very well, new devs understand it quick, and it's quite easy to read-back/adjust the code later.
I 100% agree a Tailwind project is not the best way for a new dev to learn HTML/CSS. But then I prefer the new dev to focus on great db schemas, intuitive APIs, test-able biz logic, etc. Fiddling with the mess that's HTML/CSS is not the place where I consider human attention is best spent on (or where developers pick up skills to become much better developers).
Your comment only mentions developers as the audience of HTML authoring, as opposed to users, which is a common attitude and the core problem with Tailwind.
Not sure if it helps, but if we get our first blind user I will gladly make some admends to make it more usable for them.
It seems that Tailwind is now blamed for the mess that is HTML/CSS. Tailwind certainly allows for accessible designs; it may not be the ideal solution, sure, but what we aim for is "good enough".
Isn't this slightly backwards? Why would blind users sign up if the platform isn't usable for them in the first place? It has to be usable for them for them to become users :)
I have heard "we don't have blind customers" argument many times before. Apart from ethical issues that this raises, ADA requirements, technically, don't care if you have blind users or not. Accessibility is still required...
Not good enough. You have to be accessible before it is needed in order to avoid legal liability.
And how do you expect to get a blind user if they already cannot use your product?
None of the doctors I build web sites for are currently blind. I know this because I talk to them regularly. But I still build the web sites for the future, when HR might hire a doctor or nurse or other person who is blind, or partially sighted, or has trouble with their muscles, or has difficulty distinguishing colors.
Doing the right thing isn't that hard. Not doing it is just lazy.
How will you know if they are unable to use your site? They'll just leave.
Side note: if you aren’t deliberately choosing semantic elements and instead dropping aria attributes onto a bunch of divs this is an anti-pattern.
I feel like old-school frontend devs bring up accessibility as a kind of bogeyman.
It reminds me of the myth that CSS style X or Y breaks accessibility "because screen readers expect semantic CSS classes". Zeldman (of A List Apart) promulgated that disinformation for years, until someone actually told him screen readers don't work that way. 90% of people who use a11y as a rhetorical cudgel have never actually used AT themselves.
I don't use Tailwind so I don't know if it makes it easier or harder to do the right thing when needing to hide something from everyone or only visually hiding something. Because it's CSS, it can't take care of only hiding something from assistive technologies.
I’ve usability tested and performed user research with many users needing assistive tools and I’ve used them myself as part of design.
Basic HTML authoring is good practice for many reasons.
Disability software that uses both the markup and the on-screen visual for decision making is likely imminent and would render most of this no longer necessary.
Claude Cowork is already doing navigation and web browsing by screenshot showing this is possible.
The conversations here regarding UX? (Acting like it’s black magic, not basic empathy?)
The exact same disconnection exists between dev and abled users.
Treating markup and styles separately is great, in principle, but you'll always need additional markup for certain things. We knew this going back to the early 2000s.
There is nothing about Tailwind itself that forces you to use divs and spans instead of the appropriate HTML tag.
Documents and interfaces are different. Tailwind makes a lot more sense for interfaces. You can use Tailwind for the interface and scoped HTML selectors for other content.
Tailwind is around 4x faster and has practically no overhead compared to writing a complex CSS codebase. Whatever you think of it, this is always a benefit in its corner.
If a power tool is poorly designed it may not force me to hurt myself but if it makes it easier that’s a problem.
Every time someone says that Tailwind sucks, it’s like hearing the old me speak.
The summary: write your CSS in specificity order [1]:
/scss/
├── 1-settings. <- global settings
├── 2-design-tokens <- fonts, colors, spacing, etc.
├── 3-tools <- Sass mixing, CSS functions, etc.
├── 4-generic <- reset, box sizing, normalize, etc.
├── 5-elements <- basic styles: headlines, buttons, links
├── 6-skeleton <- layout grids, etc.
├── 7-components <- cards, carousels, etc.
├── 8-utilities <- utility and helper classes
├── _shame.scss <- hacks to be fixed later
└── main.scss
ITCSS basically does away with specificity wars in a CSS codebase. Usually the only place !important is the utility layer.[1] https://developer.mozilla.org/en-US/docs/Learn_web_developme...
Like many new-ish CSS features, adoption is low; around 4-5% from a crawl of 17 million sites [1]. It's been available in all major browsers since 2022.
I'm generally addressing developers who are never going to use any (or very little) modern CSS [2]. There was a thread on HN where some participants complained about "all these newfangled CSS features". Several didn't see the need to learn CSS Grid, even though it's been available for nearly 10 years. (Aside: I really disliked the floats/tables-for-layouts era, with the requisite IE hacks.)
There are lots of developers who don't see a need to use features they weren't using in the late '90s or early 2000s. For a lot of them, they'd rather use the devil they know.
There’s a huge gap between web developers who speak at web conferences, appear on CSS-themed podcasts, and who are members of standards bodies vs the 9-5 developer that works for some insurance company or school, who's not a CSS enthusiast or hobbyist. Using ITCSS would be awesome them.
Finally, there's nothing unreliable or non-native about ITCSS; it's just CSS where the layers are in specificity order. It doesn't get any more native than that.
They're admittedly less useful if you're already using component-based design. That's closer to something like BEM in hyper-targeting each element.
If I look at their component library, they also do the work of including aria attributes for you https://tailwindcss.com/plus/ui-blocks/marketing/sections/pr... (first exsmple with free code I've found).
If we're not talking landing pages, which are more like digital brochures, I always start with markup and then add css classes on top.
Using ARIA attributes instead of semantic elements is bad for accessibility.
Sure, if there is a HTML element that works then use it, but not every UX pattern is expressible in HTML without specifying roles/attributes (e.g. tabs [1]) and not all browsers support recent HTML elements/attributes (such as using details/summary for accordions).
ARIA patterns [2] has a list of examples for UX components and their examples specify/use ARIA roles/attributes.
There is a fair amount of people that disagree with the premise that it should be separated in that way (Including me).
I personally like this essay by the author of htmx on the topic
https://htmx.org/essays/locality-of-behaviour/
Also just better composition imo.
Practically I think this means components of scoped css, html, js.
People never seem to have the same complaint about mixing or separating app code and sql in the same way?
tailwind’s biggest problem is that it doesn’t make this distinction well.
In a sense this is a strength because it probably matches the amount of effort most devs/orgs who don’t focus here are willing to put in to the problem; this worse-is-better solution is functional enough especially in settings where component separation has already been adopted. Along with some decent baseline design tokens, it’s enough for people who don’t want to care more, especially if they don’t ever particularly see the consequences of hyperlocalizing implementation.
If your project has someone whose job it is to think through design systems and how they’re expressed via CSS, you can do better. If you don’t, you can do worse.
And personally, I’ve seen a LOT of discussion about separating SQL and app code. There’s a similar tension. Wrapping queries in function calls often means fewer duplicated queries (often painfully verbose) and opportunities for dumb security mistakes, but reduces the expressive variation the raw query language provides, and many systems and devs behind them end up pursuing balance between the two… or outsourcing the decision to an ORM or other data access layer whose tradeoffs also probably have shortcomings but at least they get to worse-is-better stop thinking about it except at particular pain points.
It’s like arguing that all of your source code should go in one big file because one file is less than two files, which means greater localization.
There was never any separation of concerns within the HTML code, the class="" property is in the HTML and that is the styling info. Devs took the idea of separation of concerns of content, presentation, and behavior as separation of technologies: HTML, CSS, and JS, which is not the same. So they tended to think, "oh no, with classes I've got presentation code in my content (HTML) and I need to put it all in my CSS." But HTML is not content, it contains content. And all the separation of concerns is done with how the HTML is written.
For example take this code <h2 class="h2" data-index="0">Bleh!</h2>
That has separation of concerns. The content is Bleh!, the content semantics are h2, the styling is all in the class, and the data-index is used only as a hook for javascript. Violating separation of concerns would involve using those properties for multiple concerns. Particularly the h2 class="h2" part. It looks a bit silly at first glance, particularly if you have a bunch of <h1 class="h1"> and <h3 class="h3">'s in the codebase. But that has proper separation of concerns, and I have many times run into cases where I want an <h1 class="h2"> or <h2 class="h1">, and in those cases, because I have proper separation of concerns, all I have to do is change the actual content layer to whatever is appropriate without worrying about the presentation layer changing because someone put an h2 { font-size: 1.6rem; } in the css.
The only difference between the old-school approach and the Tailwind approach is the API between the HTML file and the CSS. The old-school approach tends toward terrible abstractions because devs are trying to code the presentation for an element while feeling they need to describe the presentation in as few terms as possible, because they think that amount of characters is separation of content. Tailwind takes the approach that the class property is the presentation layer and you can use your words to describe it clearly.
I'd add that what I've seen with the older approach almost always leads to much more co-mingling of concerns (maybe because those devs get so focused on "all style should be in the CSS"). That's when I see things like ul > li { padding: 1rem; }, which is fine until you decide to change it to an ol. Or even .foo > .bar { ... }, which is dependent on the structure of the content.
Yes, Tailwind is ugly as sin but it's effective.
I don’t know anyone whose concerns with “presentation” in markup included the presence of classes — the dominant understanding among people I’ve known who care about this is that classes are semantic in the markup with names chosen for that purpose and they have presentation attached in stylesheets.
Tailwind gives up on that separation. There can be some worse-is-better benefits to that, especially for teams that don’t have anyone whose role is to care about this. But the “ugly as sin” is a signal about the shortcomings in the tradeoff.
The class attribute (not "property") is in the HTML because it's part of HTML. It's markup. Element classes weren't created either by or for the CSS people when CSS came along. The class attribute predates CSS by years and has no more relation to "styling info" than the id attribute does.
This is precisely how I do it.
Code that generates HTML. Once I can see all the content on the screen in some kind of Netscape Navigator 1.0 nightmare, then I go back and add styles to make it look pretty.
It's not hard. It just requires thought and planning.
(The best planning tool I've found is a pencil and grid paper, not the web design SaaS-of-the-moment. However, it's surprisingly hard to find good pencil sharpeners these days.)
EDIT: ignore. I can see you have some links in your profile. Will check it out.
If the first tool in your tool chest is to change the markup, then it doesn’t matter which method of styling you apply. If your first goal is clean markup and accessibility…then It doesn’t matter which method of styling you apply.
there is a reason why tailwind got as popular as it is today. And it only highlights the gaps in either what HTML and CSS provide for the task at hand or the difficulty in that approach. This must not be lost in any criticism.
another observation is none of technical user interface decisions or discussion emphasis on the tree data structure that is inherent to every major user interface rendering mechanism relevant today. there are inherent benefits and drawbacks of it being a tree structure that neither of the developers nor the framework leverage. when thought of as a tree, it benefits from adding certain constraints and naming conventions that allow more artistic expression using just HTML and CSS that I have not seen tailwind or any other framework encourage
But sure, if you have <Title>, <Header> and <Button> components etc. instead of using HTML elements <h1>, <header>, <button> etc. directly, then why not stuff the CSS into the components as well? It all depends on whether you prefer to use components, HTML elements or a combination as your favourite abstraction.[0]
[0]: https://mastrojs.github.io/blog/2025-11-27-why-not-just-use-...
I think that upside became more prevalent in the reusable components era, whereas previously CSS was targeting an entire HTML file (and thus the reasoning was more like SQL query than "this one element's styling").
With LLMs I think this upside is much smaller now though.
With LLMs Tailwind wins. Because it's a very restricted set of classes. With regular "separation of concerns" CSS, LLMs will happily just pile on more and more and more CSS because they can't really analyze the code that's already there, and will miss and re-create huge chunks of CSS. Or write increasingly hyper-specific CSS to fix reported issues.
Anecdotally: in a side project I now have 10k lines of "pure" CSS generated by LLMs on top of Tailwind. The web part of the app is ~20k lines (not all of them are rendering anything on screen). No idea how to fix it :)
Unless you're coding on a VT100 terminal, you just put the HTML in one window and the CSS in another. Subdivide as necessary, or as your monitor space allows.
Heck, we were doing that back in 1989 on IBM PCs with MDA displays.
If your CSS is so out of control that you can't wrap your brain around it, it's time to refactor or split into individual CSS component files.
But more seriously, I should have been more specific. Having the second file open in a split pain isn't that big of a deal, but having to navigate and find the right selectors can be. If class names are used well then it's pretty easy to find those, but my experience with that is riddled with inconsistency when I'm not the one who wrote it.
On that note, it's also much easier to review CSS changes in pull requests when they are right in line with the file. Otherwise I have to do the same lookup to find the corresponding HTML, and reason about whether the selector could potentially be grabbing things that aren't obvious, etc.
I’ve made setups like that on a number of projects (ASP.Net & various .Net web frameworks). keeping clean separation of concerns, proper cascading, but also a simplified development experience where the ‘component’ file contained all relevant code, markup, and local styling.
25 years ago, I was appalled how Microsoft Frontpage could transform a very simple word document (with little formatting) into an utterly indecipherable mess of HTML that rendered correctly.
With very simple transformations, I could paste the text of the document into notepad and add just a few heading tags for the same rendered result but a much more understandable source.
CSS had a lot of promise for simplifying the HTML content, but the world tried its hardest to prevent that.
Now we have multi-megabyte monsters for simple webpages (before even counting graphics).
Is this true at all anymore, except for SEO optimized sites/content?
For apps, it’s all layout, isn’t it — and HTML, JS, CSS have all evolved heavily to support UI-first, haven’t they?
I wholeheartedly disagree. That mindset is not caused by Tailwind, but by being ignorant.
You can perfectly create an HTML document with semantic meaning and the add Tailwind just as any other CSS framework or pure CSS to it.
And DIVs do not carry meaning, they are specifically to add functionality or styling, so you can throw in as many as you like. Using them abundantly isn't good style, but the way you make it sound that they're evil isn't good either.
Also if you think massive numbers of nested divs don’t have a performance impact in the DOM when reusable components are nested (because “styling”), you’re wrong.
The problem is that HTML gives us very few tools to do anything useful. And you can only push certain elements so far. Div and span are generic elements with no semantics attached. You want a layout? Div. You want a change to a part of text? Span.
The only reason they are called "elements of last reserve" because it's only true if you remember that HTML is, has been, and forever will be a tool to display static text, badly. That's why you have article, section, p, and other text-oriented elements. But the moment you want something beyond that? Welcome to divs.
IMO this is the fundamental problem with HTML and CSS. You'll always have some part of the styling in the HTML due to needing extra divs and spans. At that point splitting the styling outside into the CSS splits your attention and Tailwind "solves" that by moving everything back into HTML.
Note that I don't like Tailwind, but I would rather have a way of styling that does not need to rely on the existance of extra divs and spans to work.
To be fair plopping a `div` everywhere started way before Tailwind. I blame React and the mess that is CSS in JS for this.
Very similar to early React where every component had to return a single real parent element (now you can return a fragment) so people chose div.
> Tailwind instead pushes the dev into a CSS-first approach.
You're putting the cart before the horse. Or forgetting either the cart or the horse. Tailwind doesn't force anything. And "semantic HTML" or "semantic CSS" are not really a thing, and have as much bearing on how many divs a page has, as Tailwind.
And the reason is simple: there's literally nothing else in HTML than divs and spans. The amount of usable primitives is absolutely laughable, and trying to combine them in any useful manner results in as much soup with Tailwind as without Tailwind.
> since part of your skill should be to produce future-proof readable HTML and CSS that it usable by all users and generally matches the HTML and CSS specs.
Which part of Tailwind isn't readable, isn't future-proof, or doesn't match HTML and CSS specs?
How is "px-4" none of that, but ".ytp-big-mode.ytp-cards-teaser-dismissible .ytp-cards-teaser-label" (Youtube's CSS) or ".swg-button-v2-light[disabled]" (Washington Post) or "legacy-popover--arrow-end-bottom:after" (Spotify) are?
> The opening example on Tailwind's website is nothing but divs and spans.
Oh no! And what are the opening examples on any of the "proper pure-as-god-intended CSS" sites?
The first example on https://developer.mozilla.org/en-US/docs/Learn_web_developme...:
<p>Instructions for life:</p>
<ul>
<li>Eat</li>
<li>Sleep</li>
<li>Repeat</li>
</ul>
p {
font-family: sans-serif;
color: red;
}
li {
background-color: greenyellow;
border: 1px solid black;
margin-bottom: 5px;
}
No divs and spans in sight.What I should've said in my hastily written comment should have been: "and other implementations of the same (or other) functionality isn't divs and spans?"
I think my only true criticisms for Tailwind example would be:
- should've probably used h2/h3 for card titles. Though this is dependent on where and how the card is used
- should've done more with the meta (number / date). But in a real world these would probably still be spans (for example, to mark them in different colors etc.)
HTML doesn't have a card element. So when you create one, you... use whatever's available. And divs and spans in HTML+CSS literally exist to manipulate layout and text.
BTW, my favorite accessible card is this one: https://inclusive-components.design/cards/ And it's probably even more weird. Demo: https://heydon.github.io/Inclusive-Components/cards-redundan... (check the CSS also)
It's trash and throwing it out is good. Not learning it is good. Tailwind is a solution to a real problem.
More importantly, AI is good at it already and it's unlikely humans will need to understand HTML/CSS at all within a year or two. There's no reason to spend time learning how the gears work, just put the cover back on
Uh… what?
Yup. Spent a decade of my career writing CSS every day, I was what you would call a "guru" and have written easily hundreds of thousands of lines of it over the years. Haven't touched a class or a stylesheet in nearly a year now, and probably never will again. Good riddance.
She writes from a place of vulnerability and honesty. Most people write to sound smart and she writes to say "I don't know it all but there are some things I discovered I want to share." I almost feel like she writes to share things with people she loves, even though she doesn't know them directly.
She spoke alongside Randall Munroe at the last Strange Loop (RIP). Some people waited to talk to him afterwards, but I waited to talk to her. I don't think she got my joke that she should rewrite her bash scripts into perl and for that I'm truly sorry.
Thank you for articulating this!
I'm not Julia, but I'd just like to put down here that this is pretty much my philosophy for public speaking/giving presentations, and I have been trying to instill it in some coworkers who struggle with presentations. It's a great privilege to be able to convey to one's peers and loved ones things that you're (likely) a bit more familiar with than they are and which may help them with some matter.
CSS is a skill just like any other technical skill. If all you do is learn the bare minimum so you can bodge things until you get something that looks right, then your ambitions are going to outpace your ability to keep things organised very quickly.
It's really frustrating to be talking with someone about Tailwind and CSS, and realize that not only do they not know what "cascading" means, they never even considered the concept might be useful in the context of a stylesheet.
And none of this really violates DRY, your unit of reuse has shifted from a CSS class to a framework component. There's nothing precluding you from using an approach like DaisyUI if stock Tailwind has too much repetition for your taste.
This is what CSS classes were made for. Of all of the arguments in favor of Tailwind, this is the one that drives me battiest. Say what you will about CSS, but "give a name to a re-usable set of styles for a component" is pretty much as fundamental as you can get.
> And none of this really violates DRY, your unit of reuse has shifted from a CSS class to a framework component.
Sure, sure. except for the inline styles everywhere. And the fact that everything is literally being repeated all over the place. But other than that, no repetition!
> There's nothing precluding you from using an approach like DaisyUI if stock Tailwind has too much repetition for your taste.
...and now you have three problems.
And when this is pointed out you’ll usually get replies that just hand wave it away as not a problem, as if things like BEM were invented for no reason.
But sure, like most tools, it starts with understanding how it works.
Whenever i have written CSS/TailwindCSS which was unproblematic to extend it was when i literally switch thinking to use least amount of properties and let the page flow.
Whenever i see tons of css i know it’s brittle and will cause hours of wasted time down the line to fix something which already should have been fixed.
I've worked with CSS since 2001. Understood the CSS rendering engine in Mozilla like the matrix and written an absolute ton of cascading CSS using various methods and frameworks. All my stuff is now tailwind and it's pure bliss.
That seems like a false dichotomy. I'm a huge fan of locality (both in software engineering and in physis) but you can also "localize" your styles by scoping them appropriately. (Modern frontend frameworks typically do that automatically for you at the component level.) There is no need to use Tailwind for that.
I meant physics of course!
No, I don’t think that’s the case at all.
I think that was true at the beginning. But Tailwind is quickly approaching the multi-headed hydra it was trying to replace.
CSS linters never really picked up steam and even with them, what's lintable is quite limited.
Tailwind, on the other hand, attempts to address a different set of problems, but I am not getting into that here -- other comments have summarized it well.
It works until doesn't, and you'll have to figure out what's going on with your code.
https://mrmrs.cc/writing/scalable-css/
And the tldr is that he downloaded and read the CSS for several major websites at the time (post is from 2016) and they were all hodge-podge of terribleness.
Maybe all the devs writing that CSS were junior, but imo it's more than CSS just doesn't have the abstractions to match the level of OCD/bespokeness that designers spec into every Figma -- move this box by _this_ much / _that_ much / etc.
It gets really easy to lean on class-based CSS and use a `<div>` for everything instead of ever learning what a semantic element is.
And that contributes to other bad habits, like writing a bunch of JavaScript to define behavior that could just be natively handled by your browser.
A weird personal irony is that because no employer has ever asked me to directly write CSS, what's actually made me better at CSS is JavaScript -- namely that my understanding of selector logic has improved a lot after picking up Web scraping.
But in my personal projects, I myself have just stopped using libraries entirely for styling.
Recently I've been using linaria which is a drop-in replacement for styled-components (exact same API) but its zero runtime. All the CSS is compiled during build (similar to vanilla extract, panda CSS, etc).
I really prefer things like styled-components or Linaria or CSS Modules where you can just write straight up CSS. If you ever decide to switch your tool you should always be able to just copy-paste your CSS away. You don't get that with Tailwind or "styles-as-objects" stuff (StyleX)
Maybe it's useful for people here. I don't use Tailwind or similar for styling, just CSS with modern frameworks like Astro or Svelte.
For every project I have the following CSS files:
- reset.css
- var.css
- global.css
- util.css
Other styling is scoped to that specific component or layout.
What Tailwind does is go fully into inline styles though. But I don't think that's an efficient approach, you also break a few other Clean Code principles along the way.
I do have some classes I sometimes apply inline, which are defined in the util.css, but the majority of styling is not done this way.
The other thing Tailwind stops from happening: class name bloat. In its absence, agents invent classes such as "card-header-inner", "feature-block-content", "sidebar-item-wrapper" – all separate naming choices. After a few months of development, you accumulate hundreds of classes that are not owned by anyone. The limit placed by Tailwind is in its vocabulary; there are no names to invent. This trade-off described by Julia exists. It's just articulated a bit differently.
I'm a fan of removing any dependencies on external libraries and writing my own solution from scratch, but there's a good reason why I decided not to do so with Tailwind: They offer an optimization for production that ensures that you never ship more than the bare minimum of CSS needed. This means you can keep your palette of color, spacing, and other options fully enumerated in `globals.css` and elsewhere, without worrying whether you're using all those variants in production. Moreover, if you're working within a framework, such as Next.js, this minimization step automatically happens when you build, without even having to worry about whether it's happening. This alone is a compelling reason, at least for me, not to migrate from Tailwind.
Also, I've never found any restrictions in Tailwind in using inline CSS that weren't readily navigable, or in implementing really nice responsive grids that handle different screen widths for instance using Tailwind's grid tooling. I definitely have solved each of the scenarios described in this article using Tailwind or a Tailwind-CSS combination, but it's true that they don't have grid-column-areas natively. Still, I haven't yet found that to be a significant restriction in getting responsive grid layouts.
I think the biggest issue with Tailwind is simply that it takes a long time to get used to reading it. We all learn that inline CSS is bad, globally scoped CSS is best, etc., and we get used to seeing clean simple HTML. Then we look at real-world code featuring Tailwind and it just looks so hard to read at first, especially because the lines are so long. I guess I just have been using it long enough that I've gotten completely used to the way it looks, but I do remember it took me a very long time to get comfortable with reading Tailwind. After a long while, I concluded that, for me, Tailwind really is more efficient and maintainable and even more readable, but it definitely took quite a bit.
Why not use native css variables?
> Moreover, if you're working within a framework, such as Next.js, this minimization step automatically happens when you build, without even having to worry about whether it's happening
Again, if you are using plain css I don't think this is an issue. With any modern build system it will spit out css file for that build, right?
> After a long while, I concluded that, for me, Tailwind really is more efficient and maintainable and even more readable, but it definitely took quite a bit.
I think this sentence says it all: Any framework will be "more efficient and maintainable" once learned, even if "took quite a bit".
For tailwind I think it's an abstraction too far, but that's a decision we all do ourselves.
<div class="counter-component">
<button @click="count++">+</button>
<span class="count" :data-is-even="count % 2 === 0">{{ count }}</span>
</div>
<style scoped>
@reference "tailwindcss"
.counter-component {
@apply flex items-center gap-2;
button {
@apply bg-gray-800 text-white;
}
.count {
@apply italic text-teal-500;
&[data-is-even="true"] {
@apply text-rose-500;
}
}
}
</style>Lately I've been enjoying Open Props[0]. It's a library of CSS props/ variables that helps structure a design system. I like it because it's CSS-first, so like OP experienced moving off TW, I've learned more CSS, and it works with the browser not against it. It also provides some sane defaults for anyone less interested in fiddling with precise cosmetics.
My favorite is when colleague A broke something from colleague B, who fixed it but broke sometimes from me, and I fixed that and broke what colleague A did. The process repeated once more and it landed again on my desk, where I said wait a minute, I've been here already. We were than able to fix all three things at the same time.
So it's difficult to keep track of everything.
- AI already have data about its classes in their training data - No conflicting styles
This means that AI doesn't need to reference any existing stylesheets when generating new styles, which is great for context management.
With custom CSS, you'll have AI read existing stylesheets because otherwise its going to write conflicting styles or rewrite stuff you already have. This can be a problem if you have large stylesheets that take too much space in AI memory.
We actually loved it so much that we’ve taken over maintenance of a fork, and just released our Pico successor candidate: https://blades.ninja/
to be tracked here: https://github.com/anyblades/blades.ninja/issues/7
That said, it is a good post putting all those things into one post and give a sane baseline for people who are new to this, or don't know the web's basics well.
> I got curious about what writing more semantic HTML would feel like.
This is so relatable. In the beginning of my career, I used to add so many dependencies for things I did not know. But these days, I mostly work on removing dependencies because I'm a lot better at using the web platform. I treat the web platform and browser primitives as materials to build what I want rather than a blank canvas to paint things from scratch.
We actually loved it so much that we've taken over maintenance for a fork here: https://github.com/anyblades/pico
css applies attributes to objects via graph queries
the queries are tightly coupled to the tree. you must work hard to avoid scatter gun edits now. it doesn't make much sense to have attributes stores in a separate location to their use
it would be like assigning all of your instances attributes using decorators
The HTML bloat was really tough to deal with. I spend far more time in HTML than I'd like, and having more Tailwind classes than I do semantic HTML was really tough to look at.
I've settled on using vanilla CSS and applying styles per-page on an as needed basis. For example, include base styles (reset, primary theme, etc) and then include marketing styles (or: blog styles, dashboard styles, syntax highlighting styles, charting styles, etc).
It keeps each page light and minimal. Reading the HTML is easy. Styles stay consistent across any pages that share styles, etc.
Building an application you use this as your utility layer that gets you 80% and for the rest you use an application specific custom css to write the parts where css is the best.
The same goes for CSS. Everyone bolded, and highlighted their experience with Bootstrap but missed the CSS. I did used Bootstrap, Foundation, Skeleton, Bourbon, and many others, especially when working with the team, so we all can speak the same language. This is true for Tailwind too. I remember when Tailwind was still in alpha and I realized that was the perfect tool to bring the team together and move fast. I was able to use it both as a utility and like most other people as the HTML polluter (but it worked).
If one is keen, it is always a good idea to learn the core - HTML, CSS, JavaScript; all the frameworks that wraps them should just be syntactic sugar. Bootstrap came and went, so will Tailwind.
PS. With AI/LLM Coding Assist, writing in plain CSS is becoming beautiful again. I can outline what I want, give it a checklist and make it do the strenuous part of writing them. I don’t even have to remember the cascades.
- Engineers never learn to properly use developer tools to debug CSS
- Components get gigantic bloated piles of classes that are not human readable
- Those gigantic piles of classes get logic in them, that often would have been easier to write as a CSS selector. Tailwind developers learn to write a JS ternary operator with a string of classes instead of ever learning how CSS selectors work
- Those ternary operators get too complicated. The engineers write object maps of Tailwind classes, or export consts of strings of Tailwind classes to use later. Those object keys and const names are what the CSS class names could have been if they just used CSS. They literally re-invent CSS classes, but worse.
- Tailwind classes can't be migrated. You can migrate CSS to Sass to CSS modules to Emotion CSS to etc mostly just by copying them over, because all of those are CSS (with some quirks). Tailwind classes are non-transferable
The happiest medium I've found was in an organisation of around 200 UI engineers: scoped CSS so that engineers can work with autonomy without colliding with other engineers, plus Tailwind for quick band-aid fixes.
Tailwind classes are literally vanilla CSS classes. You can copy-paste their definitions directly
I like tailwind because it lets you spend more time on things that matter and not bike shedding styles , it just doesn’t matter, zoom out more.
It scopes CSS to components by default, and keeps HTML, CSS and JavaScript seperate.
<template>
<!-- Largely just HTML -->
</template>
<script setup lang="ts">
// JS/TS as you would expect
</script>
<style scoped>
/* Component scoped styles here */
</style>
Very clean, easy to understand, and (as someone who started hand writing DHTML) it still feels very much like DHTML with more convenience and modern affordances.[0] Vue SFC docs: https://vuejs.org/guide/scaling-up/sfc.html
What you want to share/cascade is variables, not styles. Styling components makes it easy to make sure the styling of each component is isolated and doesn’t have unintended cascading effects. When working this way, using Tailwind is as much a good pattern than, say, CSS modules (which I like too).
I'd like to think that LLMs help with the first approach, I'm certainly now a little more curious to try plain CSS again.
> Builders value getting the work done as quickly and efficiently as possible. They are making something—likely something with parts beyond the frontend—and are often eager to see it through to completion. This means Builders may prize that initial execution over other long-term factors.
> Crafters are more likely to value long-term factors like ease of maintainability, legibility, and accessibility, and may not consider the project finished until those have also been accounted for.
> In my view, the more you optimize for building quickly, the more you optimize for homogeneity.
@import 'tailwindcss';
p {
@apply text-justify;
@apply bg-slate-300 dark:bg-slate-800; /* Second rule just for colors */
display: block; /* regular CSS */
}
I used to be a big Tailwind hater because putting all those utility classes as inline styling into my HTML is a crime against nature. But this way I get the best of both worlds. Tailwind is really nice as higher-level building blocks and saves me from writing a bunch of media queries.It’s really not when working with components instead of pages, and when working with variables properly
The creators of Tailwind wrote the brilliant book "Refactoring UI" [0], which presents a systematic design system, introducing ideas such a type-scales, color-scales, spacing, and tactics to minimizes the cognitive burden on the designer by forcing design choices. The ideas presented in this book basically are tailwind classes!
When you build with Tailwind, everyone is speaking the same design language, and you end up with harmonious designs, even when components came from different projects or designers.
I disagree with the author's approach. It's basically just copying the utility classes from Tailwind and implementing them in an unergonomic way. Perhaps the best idea is component level CSS which is something that's been enabled by better tooling. I would implore anyone who doesn't really get Tailwind, to read the origin story [1].
[0] https://refactoringui.com/ [1] https://adamwathan.me/css-utility-classes-and-separation-of-...
Atomic CSS really solves problems that only exist if you're holding the tool wrong, in my humble hot take.
Get the TailwindCSS lifetime membership. Costs about $50 if I remember correctly, but they give you all the UI blocks and CSS components, and then you can simply create a frontend-design skill based on Claude's (https://github.com/anthropics/claude-code/blob/main/plugins/...) that instructs the coding agent to only use TailwindCSS catalyst and UI blocks (you'll have to download these).
This is how I built my own website.
I don’t believe Tailwind is inherently worse than pure CSS. If Tailwind had existed from day 1 on the web and you had learned it first you probably wouldn’t say this. In fact, if Tailwind had existed first somehow, and someone came up with CSS as we know it as a new revolutionary library, I’m not sure it would have succeeded.
I still like it though. it’s one of those abstractions that actually helped me learn. I would go to the tailwind doc pages and see the underlying css of any class.
There were some other frameworks I got excited about: vanilla extract and stitches, both made by some really talented people. I wonder why those never quite got the same traction…
Just using tailwind and anchoring around a design system like shadcn is just way easier for a team to align around than somebodys made up css language.
How I refactored my rats nest of CSS back to tailwind.
https://docs.google.com/document/d/1oIb025h3UcHMJA1zPtk1kauo...
<button class="bg-blue-600 text-white px-4 py-2 rounded">
With style: <button style="background-color: var(--color-blue-600); color: white; padding: 8px 16px; border-radius: 4px; border: none;">
Now more interestingly, Tailwind with hover and focus styles: <button class="bg-blue-600 hover:bg-blue-500 active:bg-blue-700
text-white px-4 py-2 rounded transition-colors
focus:outline-none focus:ring-2 focus:ring-blue-400">
That’s not possible with the style attribute.Even more interesting with Tailwind, a div with dark mode and responsive styles:
<div class="
bg-white dark:bg-zinc-900
p-4 md:p-8
rounded-xl
shadow-sm dark:shadow-none
border border-zinc-200 dark:border-zinc-700
">
That’s not possible either with the style attribute.Now your first instinct might be to "that’s unreadable", but keep in mind HOW you actually read and write this code. You’re not actually reading it to understand what it does like you do with iterative code. You see how the browser renders it, and you just adapt the code. Tailwind code is mostly write-only and maintained by viewing what the component looks like. This code doesn’t need to be reusable either, the whole component needs to be. The Tailwind code inside is unique.
I think this helped me finally understand the chasm between tailwind proponents and me. I just don't think I'll ever be part of the "keep painting each room a slightly different shade until it looks right" camp, when there's the "you can buy all the same color paint ahead of time, and even have some left over for the next five rooms you build" option right there.
Yeah, tailwind as write-only code definitely tracks. I guess some people like that. Not my bag though.
You’re still not getting it. That’s NOT what Tailwind is, because Tailwind works in a design system way, so when you use text-sm or bg-sky-400, you’re using variables that can be configured to suit your needs and keep a consistent design everywhere. Tailwind defaults and configurability played a huge part in its success.
I’d add that almost all code is like that, if you mean you only write it once and only look at it again if you need to make a change. And with Tailwind you generally only need to look at the one component, instead of having to go to a separate CSS file to look, and then look through the codebase to see if that code is used anywhere else.
E.g. how do you style a child on parent hover with the style attribute?
Nobody cares about true REST (modern day RESTful is a different thing), HATEOAS or semantic web. People tends to simplify things.
We probably can live with just 7 html tags,<title>, <style>, <div>, <form>, <input>, <button>, <a> and CSS.
next thread
In a work setting, beware of DIY Syndrome. Move away from an established tool, and now your on the hook for documentation, onboarding and maintenance. When the one dev who cares about that leaves the company, everything will fester. It never ends well.
Separating HTML and CSS into different files is just like separating a bunch of methods/functions into different files, or splitting one monorepo into git submodules. Yeah, it sometimes makes sense, but if you're doing it for the sake of separating things then just stop.
I think the only point of Tailwind is to make front end devs realizing how much separation of concerns is misunderstood and misused as a dogma. Once you realize that you can ditch Tailwind if you like.
What you see in reader mode is the content layer. HTML is a part of the presentation layer.
I tend to work closer to the latter end and find that both React and Typescript are extremely helpful to make my code extensible and maintainable. YMMV.
But for mid/large projects, I find that TypeScript brings sanity to JavaScript.
I love some quick and dirty JS project. But after a certain project size I begin the see runtime errors like undefined, NaN, 'false/true' concatedted to URLs, and so on. TypeScript eliminates a ton of those.
Frameworks like React that add structure to the data flow, component encapsulation, and a huge repertoire of patterns to train on, plus Typescript for immediate compile-time feedback loops… those are what LLMs thrive on.
I have these two https://reddit.premii.com and https://hn.premii.com/ both works without any changes. Reddit will stop working once they kill the apis but until then it will work.
Hmm, yes, simply have the LLM write good with no mistakes.