295 comments

[ 3.3 ms ] story [ 344 ms ] thread
"Build times reduced", "no more @tailwind directives", "No more js configuration", "Designed for the modern web".

To me, this screams "CSS now can do everything we used to do ourselves, but let's keep pretending that we are still needed somehow"

Really!? Is that really what you got out of it?

I understand you're not a fan of Tailwind, so perhaps say what you dont like about Tailwind instead of creating a strawman and attacking it.

Also, shame on you for poo-pooing on someone else's open source project and people find useful.

Yeah, I tried (not so hard) to like and use tailwind, but I've been using bootstrap for so long, and for my very simple needs, bootstrap was a better choice. But I wouldn't go around saying, "tailwind is unnecessary for everyone."
I'm with you. Tailwind would be great if it could be SASS'd but Tailwind is a post processor and it would be silly to build a post-post processor just to make tailwind reusable. It simply isn't a good tool for large enterprise applications. Toys, home projects, sure. But then, why learn CSS twice for occasional use? Until they solve the post processor problem, I'll stick with bootstrap. But if they do, I would definitely switch. That would be the best of both worlds.
"What I don't like about Tailwind" has less to do with Tailwind itself and more about the violation of separation of content and presentation that they push so hard.

> poo-pooing on someone else's open source project

This is not some young kid doing free software out of kindness. This is a company making millions of dollars in revenue in a closed source product (tailwind UI), which is built on a foundation (tailwindCSS) that is becoming less and less needed.

Often content and presentation are part of the same package. In these cases, separating them makes maintenance of sites harder.
> and more about the violation of separation of content and presentation that they push so hard.

As someone who's done it both ways with web sites, that separation sucked. Having to figure out which style in my CSS file was messing things up was always a pain. And Tailwind tends to be "local" by default, limiting the damage done to other elements when I style an element.

In my larger experience (not just with web sites), whether separating content and presentation is a good idea varies widely from use case to use case.

What did you need Tailwind for before that you couldn't do in normal CSS? Doesn't Tailwind map pretty much 1:1 to CSS?
> Doesn't Tailwind map pretty much 1:1 to CSS?

Much of it does, but not all of it.

Do you have an example that Tailwind can do that can't be done in CSS?
I'm going off a claim from the Tailwind site :-)

The original question wasn't whether Tailwind can do something CSS can't, but whether it was a 1:1 mapping.

Can regular CSS do media queries all within the element's style attribute?

I believe Tailwind also utilizes JS to get some convenience features to work.

Oh gotcha, I must have just misunderstood the previous comment.

I want to say that tailwind also can't do inline media queries, but that's getting really nitpicky and pedantic. You can at least add a class inline that Tailwind creates a media query for in CSS, that is really handy.

Tailwind doesn't generate any JS at all. The final build is 100% CSS.
Every programming language maps 1:1 to CPU instruction sets, but very few humans want to speak CPU language directly…hope that helps.
Programming languages are more human-readable than CPU instructions, as opposed to Tailwind, which is less human-readable than CSS.
It's a horrible way to do what css can do but in a dumber way with added tooling. It is used by people that don't know css and this is where the problems start
I’ve been writing css/scss/stylus/linaria/whatever styling stuff for 18 years and I think tailwind improves life much more for css knowers than for css noobs. I prefer it over raw css for sure - I’ve written the same shit enough times that I’m happy to take some shortcuts and more than willing to pay for some tooling to do so. Tailwind hands out less abstraction rope compared to vanilla css and sass and all the rest, so much lower chance I open up a file and find some convoluted special little kingdom of abstractions that need to be handled carefully. Reduced cognitive load in the long run for a small up front learning/setup cost.
"Basically just inline CSS, but less fiddly and much more optimizable than the style attribute" was always the selling point of Tailwind in the first place.
Then, yes. But nowadays CSS is a lot more powerful and has caught up. So why bother with Tailwind?
Because of multitude of reasons. One of the big ones being never having to search through a style tag or finding a CSS file. 100% of the element styling is described in the element markup.

Tailwind was never about filling gaps in CSS.

That is atomic CSS, and it predates tailwind by quite a bit. There is a huge marketing push behind tailwind. If you look into who made it, you'd see it wasn't their first attempt.
Do you have any links describing what you mean? I'm not a CSS guru, and perhaps I know only the "old" CSS. I did recently learn Tailwind and it's way nicer than the "old" CSS.

If modern CSS makes styling as easy as Tailwind does, I'd love to read about it.

Why do you keep saying CSS has “caught up”? Tailwind has always just mapped to CSS, so you’ve always been able to do anything in CSS that you could do in tailwind. What has CSS done that makes you see no value in Tailwind today where you used to see value?
CSS has become more confusing over time, not less confusing, so the upside of a utility class approach like Tailwind is also improving over time rather than decreasing.

Tailwind solves css confusion by presenting a “paved road” for many tasks. Want to do “thing”? Just look up “thing” in the tailwind docs, add “thing-2” to your class, done in 2 minutes. Rather than look up “thing” on google, skim several articles, then write 4-10 lines of CSS, done in 30 minutes.

As CSS has gotten more complexity from new capabilities, solving various tasks with it feels more and more like a research project. Like centering a div vertically and horizontally - there’s now 3-4 generations of solutions for this task:

1. Hacky stuff with position: absolute or floats

2. Flexbox approach. Hope you remember the 6 different attributes you need to set! Oh, there’s a new shorthand for flex now? Cool! More stuff to learn.

3. Grid approach. There are a bunch of different ways to structure a grid centering approach. Hope you remember how grid templates work!

With tailwind, just add 2 classes, done.

> With tailwind, just add 2 classes, done.

But you can do that with a library of SASS mixins as well.

Going through some of the answers I'm noticing that another "issue" I have with the tailwind approach is that it works by providing a post-processor when in reality most people just need a simple preprocessor and macro system.

Sure? I don’t see how that’s an argument for CSS “being advanced enough” - SASS ain’t CSS.

I like SASS (I wrote a lisp in SASS in 2011 lol) and that’s actually how I think about Tailwind utilities - it’s just using SASS mixins directly in your HTML. I would rather use Tailwind because it will take 1/3 the levels of abstraction, 1/4 the keystrokes and 1/2 the files to do the same job to:

1. Pick a class name (myclass) if people are using BEM or something this requires some algebraic thinking.

2. Write the class in file.scss to define the class and include mixins A, B, C

3. Add class=myclass in my html.

Vs tailwind:

1. Add class=“A B C” to my html.

I don’t really get pre processor vs post processor, it’s a build step to run at some point before I deploy with either tool that will produce some css files. ¯\_(ツ)_/¯

> I don’t see how that’s an argument for CSS “being advanced enough”

That's a separate argument.

I hear mostly two justifications for tailwind:

1. It is (or used to be) hard to do things in CSS like variables, calculated properties, themes, scoped rules / namespacing. (Pre/Post) Processors are going to be required anyway, so we might as well use Tailwind

2. It gives frontend developers and designers a common language (the utility classes) which makes it easier to establish workflows.

My argument for (1) is that CSS already supports a lot of things that used to require processors, and (2) could be achieved with a simple "library" that could just be imported directly.

I agree neither of those seem like good reasons to pick tailwind.

My take is that it removes needless indirection in any codebase that already has “components” - react/vue/solid/etc, template partials, functions that return html strings, whatever. See comment here: https://news.ycombinator.com/item?id=42804831

For that reason, plus it’s concision, I find it more productive use of time compared to css-in-separate-file.

If you don’t have components for separating semantics from presentation, then tailwind is less a good fit.

> I don’t really get pre processor vs post processor, it’s a build step to run at some point before I deploy with either tool that will produce some css files.

Not quite the same. If it's only a preprocessor, the tool is only dependent on your styling code. A post-processor needs the whole application.

It's a lot easier to add or remove a pre-processor from your development process, and for those that want to consume your styles it is a lot nicer when you don't have to adopt their tooling as well. E.g, I can create a "utility class library" in SASS, generate the CSS and let people just import that directly into their web pages. Is that possible to do with tailwind?

A concrete example that seems like a no-brainer to me: let's add a little padding to the top and bottom of an element. "py-2" Done. In CSS, specifying padding (or margins) is 4 values... except I forget which is the first one. And what units should I use... px, pt, rem, em. Inline, same-page style, or an external .css file? If not inline, what should I name the class? Vanilla CSS literally requires 10x more time and mental attention.
> "py-2" Done. In CSS, specifying padding (or margins) is 4 values... except I forget which is the first one.

False dichotomy. You are not stuck between tailwind and "Vanilla CSS", and one can solve the issue you are presenting with any reasonable set of SASS mixins.

> If not inline, what should I name the class?

Also solvable with good old SASS.

You can using padding-inline and padding-block with var(--spacing-2).

Tailwind is styling utility classes and design tokens in one. There are premade design tokens you can use the CSS styling though.

But it's not just inline css though. The length of inline css string would almost always be 3 times longer than tailwind classes string.

Also inline css doesn't allow media queries, pseudo classes, etc., which is a big deal.

If you going to hate on it, at least try understand what it is and why people use it.
It's not "hate". It's just that I don't see the value that it brings today.
Whether you enjoy utility classes isn't really related at all to what css supports.
Maybe you are making my point?

If tailwind was "just utility classes", fine. But what business would it be there if they just published a bunch of CSS files with their styles?

With modern CSS, what problem are they really solving now?

As someone who made a competing product along these lines (that got no attention or traction): Tailwind gives CSS a "place" in the codebase. It benefits orgs, not necessarily apps. I didn't get it at first either. But it's very useful to the people to whom it's useful.
> Tailwind gives CSS a "place" in the codebase. It benefits orgs, not necessarily apps.

That is a better argument. But couldn't we be able to achieve that by, e.g:

- Create one standard HTML document with a predefined structure and including all the web components needed by your product.

- Having all designers and frontend developers developing their CSS (or SCSS) against this single base document

This would be basically the CSS Zen Garden approach. It would still keep separation of content and styling and it would create a "place" for styling code.

There are more "modern" ways to do this for large organizations like Storybook. Tailwind is a proposition for a small business that has a very small budget, want to buy a ready-theme and then make slight modifications. In a sense, no, it doesn't make any sense beyond that to use it. And once you use a good React/web-components framework, you realize there isn't really much value there as you shouldn't be really changing the CSS from page to another.

The process for large orgs is tedious and too lengthy/expensive for the small ones. Imagine having to go through planning, visualization, creating the component (or adding props for customization, writing e2e tests, publishing it to storybook with docs, and then finally adding it to your page and get it pipelined in the merge CI/CD process. A small org with tailwind just open the page in question and add a class to the html element.

This works for products with a very limited scope that are mostly content focused, with a very small design team so everyone can agree to use the very limited toolkit in standards.html. The approach of saying “All ui shall only use these 29 components, anything else is forbidden” is not going to fly in a company with 10s of designers and 100s of engineers.

We tried this style at Airbnb and it turns out forcing all UI changes - from either designers or engineers - to acquire a single exclusive lock on standards.html leads to a fuckton of contention and frustration, and soon people are just going to yolo their own thing totally ignoring the pristine blessed system because the system doesn’t work.

The art of design systems isn’t a single technical approach - it’s finding an optimal workflow so your design engineers can build a UI toolkit that your product teams will actually adopt and contribute to, within the constraints of your existing tech stack & organization.

As others have said, this is exactly what many large orgs do, but in a slightly higher-tech / more polished way with tools like Storybook, essentially creating their own CSS libraries and component libraries.

IMO a decent analogy is that Tailwind is to the above as something like Shopify is to being large enough to build your own ecommerce platform from scratch.

What is stopping from someone just turning all those utility classes into a single CSS file and completely get rid of the post-processor stuff?
> I didn't get it at first either.

maybe you got it wrong? CSS already have its place and work great as .css files

In my experience, the main problem it solves is the fact that styling in react is still a pain in the butt.
What value does Rails provide to Ruby?
Does Ruby have an ORM/HTTP request handler/URL router in the standard library?

I am not sure I follow the analogy. If all you are taking from tailwind is the utility classes, fine. This is the part that provides value. But tailwind is not just that, is it?

Rails is a fully formed opinion on how you should write a web app in Ruby and all the various technical components you need to fully realize that opinion.

Tailwind is a fully formed opinion on how to use CSS (utility classes etc.) and all the various technical components you need to fully realize that opinion.

Thinking of Tailwind as just a bunch of regular CSS utility components is misunderstanding the scope of the project. That alone has a lot of tradeoffs and compromises - the file size is absurd and you can't bundle things into components, you also can't have arbitrary values in the utility classes. It wouldn't be a complete opinion on 'the best way to use utility classes', or however you want to frame Tailwind.

Thanks Tailwind devs! It’s a testament to the success of the concept and the quality and consistency of execution over a seriously long time, that Tailwind became how LLMs write code for the web.

Congrats on the release.

Yes, I’m a huge fan of how easy it is to whip up quick isolated prototypes in Claude artifacts.

There’s a risk of breaking changes in libs causing frustration in larger codebases, though. I’ve been working with LLMs in a Nextjs App Router codebase for about a year, and regularly struggle with models trained primarily on the older Pages Router. LLMs often produce incompatible or even mixed compatibility code. It really doesn’t matter which side of the fence your code is on, both are polluted by the other. More recent and more powerful models are getting better, but even SOTA reasoning models don’t totally solve this.

Lately I’ve taken to regularly including a text file that spells out various dependency versions and why they matter in LLM context, but there’s only so much it can do currently to overcome the weight of training on dated material. I imagine tools like Cursor will get better at doing that for us silently in the future.

There’s an interesting tension brewing between keeping dependencies up to date, especially in the volatile and brittle front end world, vs writing code the LLMs are trained on.

I appreciate there are people who find Tailwind useful and are productive with it, but it has this clean yet generic look that I now see everywhere, because Tailwind is now everywhere.
I feel like that's a good thing, because Tailwind's options are well-thought and work well.

I like to think of it in the same way as Inter being the new Helvetica when it comes to choosing a font for a website: lots of people do it, and it looks great, so why not?

Tailwind gives you sensible defaults, but doesn't really influence your design too much. People just tend to design the sites a certain way. Especially, with ShadCn.
This is conflating Tailwind and TailwindUI/shadcn/etc.

For the most part, Tailwind offers no more influence over style than normal CSS (okay, there's some exceptions... things like shadows are a bit more standardized, and indigo has gotten outside influence on color palettes as of late).

I heard this comment about Bootstrap back this in the day but none of my Bootstrap sites looked like each other. Bootstrap saved me a lot of time because it had a lot of utility classes (like Tailwind way before Tailwind) and it never enforced a certain look.

You just loaded the classes that you wanted (unless you didn’t download the source Sass files, but that would have been silly).

The same way everything looked like Bootstrap a decade ago.
My take on this problem is, good UI frameworks (i.e. tailwind + components) are still rare. So the vast majority of projects use a very small number of them. If 4-5 new quality UI projects popped up, especially if they departed more in their styling, we'd see more diversity.

I've come to realize with design, like much creative work, the trends really do seem to be set by a shockingly small number of people. I wish more people realized this, because I feel there are talented individuals out there not making their own, thinking they'll never be heard. But I suspect some of those people would be unlocking new UI's for a large chunk of the web if they would give it a go.

I love tailwind, used in 3 projects in the past 4 years, it’s intuitive, well documented, simple. I don’t miss the days of emotion and styled components where I would have to think of a name for every styled div in the project, with tailwind a container is just a div and a few classes nothing else. Less bike shedding discussion, less brain cycles spent naming things, less time wasted in reviews.
> a few classes

You must be working with very good product owners then. The ones I've worked with love to specify the hell out of every possible detail. Like a web form is their personal HGTV renovation. I tried tailwind once and the classes ended up being an order of magnitude more than the markup. It got hard to read, quickly.

you can use @apply to merge the various utility classes together in to something resembling a name, like

.btn-primary { @apply py-2 px-5 bg-violet-500 text-white font-semibold rounded-full shadow-md hover:bg-violet-700 focus:outline-none focus:ring focus:ring-violet-400 focus:ring-opacity-75; }

But their v3 docs seem to be very against this.

"Whatever you do, don’t use @apply just to make things look “cleaner”. Yes, HTML templates littered with Tailwind classes are kind of ugly. Making changes in a project that has tons of custom CSS is worse."

Reasons:

* You have to think up class names all the time — nothing will slow you down or drain your energy like coming up with a class name for something that doesn’t deserve to be named.

* You have to jump between multiple files to make changes — which is a way bigger workflow killer than you’d think before co-locating everything together.

* Changing styles is scarier — CSS is global, are you sure you can change the min-width value in that class without breaking something in another part of the site?

Yet... my experience using projects that use tailwind is that every button everywhere is styled the same way, but it's repeated in multiple areas. The 'kinda ugly' part, but also... it's repeated in multiple places. Trying to change the universal focus behaviour of buttons in a project like this is hard, because... I can't search focus:outline-none without finding everything that has 'focus:outline-none' on it. I can't just search/replace, because it'll impact other stuff.

So I end up spending way too much time trawling through way too many scattered specific styles all over a codebase, vs having a defined 'btn' style someplace. "well, that's just the project's fault"... possibly, but it seems to be the promoted/preferred/evangelized way of using tailwind, judging by the projects I've had to get involved with the past few years. IME, this approach may have good short term benefits, but poorer longer term maintenance, doubly so when the original people are no longer involved in the project, and outsiders have to come in to deal with it.

(comment deleted)
I agree with Tailwind's stance on this. You really don't need @apply if you're breaking things down to smaller components. I often see people have things like <ul><li className="long_list_of_classes">text1</li><li className="long_list_of_classes">text2</li>...</ul>. This is where I think we need a linter to warn against things like that. Make those <li>'s a component!
I have bern heavy Tailwind user from before v1. It actually doesnt matter where you make the class grouping. You can make it in your templating language or you can make it in @apply. I prefer @apply because the same grouping can be reused if done correctly. @apply is great.

The reason they are discouraging @appply is because its hard feature to implement and many people dont understand how it works so they get to problems and create issues. It bothers Authors so much they have always been considering taking @apply out but i think they know big chunk of the userbase would leave to different similar project.

Wait, what? You want to make every li/dt/etc. component? That's insane.
Why not just do <ul class="my-class">…</ul> and then apply the styles to ul.my-class > li ?
For buttons, I think the 'blessed' way to do it is to use (react) components and have the tailwind classes encapsulated there. It makes sense; you have a layer of abstraction where the implementation of your theme is in the "lower level building blocks" of your components. (Call it a component library if you want)

I generally only use @apply when there are some heavier external interactive libraries that are hard to style. Like for example if you're embedding markup in your application, and you need to apply a set of styles to the markup it generates, and you can't do that directly in react because you don't control that part.

> I can't search focus:outline-none without finding everything that has 'focus:outline-none'

Would a regex not work? Something like <button[^>]*?focus:outline-none

I generally use tailwind in combination with daisyui, and I don’t think about styling a lot any more beyond choosing the proper theme.
> I don’t miss the days of emotion and styled components where I would have to think of a name for every styled div in the project

I see people mention this issue fairly frequently, and it puzzles me a little. I have never once spent probably more than 1 second thinking about what to name something. Is it actually a blocker for some people? Are you really paralysed by this?

especially since with any decent CSS solution (any css in js, or CSS modules) you can reuse names
Like really, I use Styled Components, just call it a Wrapper or InnerWrapper or Row or whatever and move on
There was a time when BEM ruled (and scarred) the world. But names aren't a problem if you abandon the C in CSS and scope all styles to component.
I'd say BEM was a passing fad, but didn't rule the world. I also think tailwind will suffer the same fate, but we'll see how it plays out.
What I don't understand is why BEM is scarring. If you're talking about the reason or timing something looks different, you must have named it in that conversation. Just use that name.

"When the menu is wide, the items' icons and text should be visible. When it's skinny, only the icons should be visible. This button toggles between them."

    .menu {}
    .menu--skinny {}
    .menu--wide {}
    .menu__icon {}
    .menu__text {}
Or I could just express this in code once - in the spot where I attach the class names to the HTML - instead of attaching class names, just attach styles.
Gave it a go for several projects, but didn't like it... for big projects it gets messy, fast. It also feels like it has become the new bootstrap.

I'm very happy with my current CSS-in-JS workflow. Crafting good old css with LLM help. You just show the LLM a pic, ask for the components.... boom, done (with proper naming, etc)

This is actually one of the main reasons I avoid react when I have the option. Styling in react is terrible, I'll use tailwind with it but only as the least bad option.

If I am using a frontend framework and a build step, svelte and astro are nice depending on the use case. I can style with plain old CSS and rarely have to reach for class names, if you keep components small you can get away with element selectors and let the framework scope styles at build time.

Heck yeah, cool to see Tailwind add support for transitions without Javascript.

As a burgeoning web developer, dealing with animation libraries seems like it's not worth the effort (or at least not for something as simple as a blog), so this is much appreciated.

Looking forward to integrating this into my elixir projects!
Question for people who are good at CSS stuff. I am not.

I'm upgrading a personal Phoenix project to 1.7, and Phoenix now uses Tailwind by default. So I thought I'd try and update my one page thing to use it instead of Bootstrap.

So far, it looks like crap whereas the Bootstrap one looked 'good enough'.

What's the easiest way to get something that looks kinda sorta decent, with some nice defaults, without trying to become a designer?

Or should I just reinstall Bootstrap and be done with this.

Put your HEEx into a LLM. They understand both Bootstrap and Tailwind very well. It will probably not be too hard.
If your looking for components like bootstrap try https://flowbite.com/ for free. Tailwind also has paid components. You just copy and paste. The cool part is once you get more comfortable you can start to tweak the flowbite components.
Tailwind and Bootstrap and are kinda apple vs apple pie. Tailwind provides classes that still need to be stacked to build components.

It'd be easier if you were using some source for UI components, I've used TailwindUI in the past, but that's paid. I'm sure there are good free alternatives.

I’d say it depends on who is paying you. If you have job security and want to tinker, then play with tailwind if you want (most trendy / loud people seem to like tailwind). If however you are working on your own project / are self funded / or have a deadline just stick with bootstrap that you know, and focus on getting your work done instead of bike shedding on the UI
reinstall bootstrap and be done with it. You can look at daisyui it is closest to bootstrap. There is also shadcn ui, ui looks good but it would take you effort to port styles to your phoenix project.
I use DaisyUI to accomplish that goal, here is my demo site for an example: https://nwk-landing-kit.netlify.app

and here are the docs for DasiyUI: https://daisyui.com

The DaisyUI description of the Tailwind button made me laugh:

"bg-indigo-600 px-4 py-3 text-center text-sm font-semibold inline-block text-white cursor-pointer uppercase transition duration-200 ease-in-out rounded-md hover:bg-indigo-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-600 focus-visible:ring-offset-2 active:scale-95"

Yeah, that's not making my life easier is it. Also some of those class names are super cryptic.

They are cryptic but the learning curve is not that steep. Once you get the idea, it becomes much easier (and quite pleasant for a CSS hater like me). For example px-3 means "padding on the x axis 3 (spacing values)" and gives you padding on both left and right. There is a (rather simple) language that you need to learn and at least for me it made things much, much better. You can probably get the feel for it in several hours of building a basic website with Tailwind (and DaisyUI I would recommend).
ia that really easier than learning css directly? since you have to understand 'paddding'and 'px' ?

see https://developer.mozilla.org/en-US/docs/Web/CSS/padding

vs https://tailwindcss.com/docs/padding

I am not going to argue whether that's the case, as I never managed to learn CSS enough to be productive in a convenient (for me) way. Despite of trying many times. Whereas tailwindcss "clicked" right away and gave me the awesome superpower to build whole products without having to depend on other people. Before that I hated myself for the horrible, unmaintainable mess that I created, and double hated myself later when I had to revisit the project. Since I am using tailwindcss, I never had bad experience. Of course I still have to spend time wondering how to center some element and why it doesn't work, but that's not what I am complaining about.

It might be just a personal defficiency, but it is how it is (for me).

One of the reasons Tailwind became so popular - even more so than preceding frameworks like Bootstrap - is that a lot of people who normally liked working with CSS directly fell in love with it. It removes the extra step of editing a separate CSS file without straying far from a 1:1 mapping and eliminates most of the cascading rules that have plagued frontend for decades (`group:` and friends notwithstanding). The latter is important when working on large teams because it eliminates the name bikeshedding and conflicts.
sorry, but this is just not true. The cascading issue is still there, and it gets even worse because if you have an element with class "p-1 p-0" you cannot know in advance which will take precedence.

Of course you shouldn't do that, but it happens to be the case that Phoenix does exactly that

This is not a cascading issue. This is a "You're holding it wrong" issue. And when Phoenix does write 'p-0 p-1', Phoenix and Tailwind are not a good match.
You suddenly reminded me about another good Tailwind thing: linter will highlight "p-1 p-0" as a mistake. I've never seen linters that warn on "your-custom-p1 your-custom-p0", but Tailwind makes it possible.
If the alternative is:

.foo { padding: 0; padding: 1rem; }

then I can see the precedence but I don’t see how it’s an advantage. You can write bad code in any methodology.

That seems like an issue with Phoenix and not Tailwind or the Tailwind approach.

it's quicker to write, though. and many of these class names are the same in bootstrap, so I've been seeing stuff like 'p-0 m-1' in frontend projects for decades.

another huge benefit these days is with the styling living alongside the markup, it is very easy to use chatGPT or other AI tools to copy/paste and have changes made, etc. it is much less work with one file vs multiple. you can give the context super easily and take the results very quickly.

As someone who used and knew CSS very well, and reluctantly used tailwind, yes. I don't strongly prefer one or the other. But I will say now that I know Tailwind, when I see those large class name strings, my brain parses them shockingly fast, and they kind of melt into the background similar to comments. Also, common linter rules will order the classnames, and that they are always the same between disparate tailwind projects, all together its not nearly the annoying mess I thought it would be on first sight.
> Or should I just reinstall Bootstrap and be done with this.

That one.

Tailwind gives you tools when you want to control the design, but you’ve got to control the design.

When you just want something that looks good and don’t mind that bootstrap-y feel, bootstrap is the way to go.

(There are projects that essentially recreate bootstrap on top of tailwind, which, in theory, might give you something like bootstrap as a starting point with the power of tailwind, but I haven’t seen it work better in practice than just using bootstrap.)

Disagree.

Just get one of the tailwind UX kits and use their classes as your standard style guide. I personally use flowise as it’s free with paid more complex components if needed, but there are a bunch of others out there that fill the same space.

The same can be said about Bootstrap, though. Just get a theme to make it look less bootstrapy. I think both viable ways to go, and it just boils down to personal preference (especially for hobby projects).
On a new project, sure maybe going with tailwind + a theme/kit is a bit more up to date than using bootstrap. But on an existing page that already looked fine with bootstrap, why bother with the extra work?
That's fine (I've done it). It's just that bootstrap is better at it.
Migration guide, if anyone is wondering: https://tailwindcss.com/docs/upgrade-guide

Some breaking changes in there. May want to hold off on upgrading until LLMs come around to writing v4 code with ease.

This reservation has taken firm hold on me and has made me a slower adopter of shiny new things.

I feel alright about it from a local perspective (I'm a lot more productive now than I was before), but I do wonder what it does to the overall dynamic and incentive to write shiny new things or generally update the ecosystem.

The LLMs will get more powerful, but to what extent will their work be dominated by existing tools (with lots of existent human-generated exemplar)?

LLMs have already plateaued in knowledge imo.

There’s far less reason for humans to contribute code examples, answer questions, work on open-source projects, or even produce content knowing it’ll immediately be slurped up and resold.

Web dev will be stuck with React and Tailwind circa 2021 for a very long time.

We shouldn't really have to retrain models for them to be able to work with new versions of libraries or frameworks. That seems like a flaw in the LLM (only?) setup. One should probably be using RAG at a minimum to pull in the correct documentation and references. Something like Kapa, but not limited to a single project https://www.kapa.ai/
Renaming utilities like flex-shrink-* makes existing LLMs emit deprecated code today and broken code tomorrow. I wonder what the rationale is behind the renaming of various utilities (e.g. shadow-sm -> shadow-xs, flex-shrink -> shrink, decoration-slice -> box-decoration-slice, ...)

In new projects, I will probably use Tailwind v4 and constantly provide the upgrade guide as context to an LLM. In existing projects, I will continue to use Tailwind v3 until I am certain that it works alongside the tools used by my framework (React Router / Remix).

I’m a recent convert to tailwind. I’m very comfortable with css and I was initially turned off on the huge horizontal lines I saw in tailwind projects.

However, more and more component libraries are based on tailwind so I decided to try some immersion therapy.

Here are the top things I enjoy that was not obvious to me:

1. The class names are css shortcuts. Using them save you a lot of time. This is probably obvious to anyone who’s seriously looked at tailwind but I didn’t see that browsing the docs. I just saw nightmarishly long lines.

2. The lines look longer when you are not familiar with the class names. I initially pulled all of my class names out into a string outside my markup and included similar to how I’m used to using emotioncss. This made tailwind tolerable for me at first. However after several days I started to feel less turned off by those lines. I think it’s because I could recognize them. I will still break down a line with something like clsx.

3. clsx helps so much vs trying to entirely rely on tailwind syntax. The docs don’t discourage this at all but for some reason I thought it wasn’t idiomatic tailwind at first.

4. My app has to support a very large number of themes. Tailwind has proven to be a very attractive way of solving this problem. CSS variables are cool but the long syntax of using them is helped a lot in tailwind.

5. Adding my own custom variants is so easy and made me feel like a power user with such a small learning curve.

All of this is just my two cents to guide anyone who is like me watching from the sideline and wondering why? Why would anyone ever want to tolerate those “disgusting long lines mixed into the html”. Neo, all I see is the lady in the red dress now

It's sort of like javascript devs ignoring typescript because they never felt like they needed it. But once you start using it, it's difficult to go back.

I was in never ts/tailwind gang for a few years until I tried them.

As a once-strident critic of Tailwind for its many failings and incompatibilities with the state of the actually-modern "vanilla" web art, I am very pleased to see the huge strides they've made with v4. Being able to access the Tailwind theme through native CSS variables (they even have an example in the docs of a button component written in native CSS in an external stylesheet using native variables! Oh happy day!) is absolutely massive, and being able to use a CSS-only config is equally amazing. Finally, Tailwind feels more like it's a utility (ironic, since its claim to fame is utility classes!) which you can add to any project, rather than some bizarro "viral" framework that wants to eat sensible architectures and lives in its own JavaScript-y silo.

Perhaps all the criticism over the years actually had an effect. Or maybe they finally arrived at good conclusions on their own. Either way, I suspect many of the pro/anti-Tailwind arguments are no longer relevant, and that's a Very Good Thing. Now we can get down to business and ship product.

> I suspect many of the pro/anti-Tailwind arguments are no longer relevant

I feel there are two issues with Tailwind for me as a designer / design engineer.

* First, JavaScript/Tailwind engineers have hijacked the conversation on design. Instead of "utility-first," "dead code elimination," and "type-safe CSS" I focus more on desing systems. Whether to use Perfect Fifth or Perfect Fourth in typography for example.

* Second, Tailwind makes it impossible for me to participate in the actual craft. Design decisions get buried in React components with cryptic expressions like `flex items-center shadow-lg p-6 hover:bg-gray-50 dark:bg-gray-800 py-[calc(theme(spacing[2.5])-1px)]`. This might make sense for JavaScript engineers, but blocks/makes it hard for systematic design. Instead of expressing precise mathematical relationships through CSS, we're essentially writing inline styles with better ergonomics.

Maybe Tailwind is useful for bigger projects, but I tend to prefer component based class instead. The biggest DX for CSS is using the web inspector and directly modifying the DOM, then copying the adjusted values to the text editor. For a much serious project, I go with the balsamiq -> figma route to create an actual design system.
You can allow the inspector to access the filesystem and modify the files without having to copy/paste for even better DX.
Tailwind has solved a lot of problems. And this is coming from someone who doesn't use it half the time.

Some thoughts about this topic, not necessarily in disagreement:

- Designers seldom think in the way you describe (explicit computer-readable rules, systems of design). A lot of designers are coming from crafts that are more implicit. It doesn't surprise me design business logic is not the topic of conversation.

- You need to update your tailwind classes to reflect your design business logic. Don't do "bg-gray", do "on-surface-emphasis" or whatever business logic. This is just a simple config change.

- You probably brought up modular scale as just one example, but modular type has become near myopic dogma of frontend engineers who haven't had any typesetting experience. A scale of 1.25 vs 1.5 is so in the weeds as to be useless. There are so many alternative ways to set type (e.g. take lessons from CJK typesetting) or innovate typography on the web (e.g. build your own leading-trim implementation!).

I'm a designer, so I absolutely think in terms of design systems where typography is just one part of the puzzle. There are, of course, many ways to set type — but the point was: no Tailwind engineer talks about typographic scales in the first place. Systematic thinking is absent, which is naturally built in CSS.
I'm kind of surprised why this is even relevant to you. The designers I know work in Figma. The designer and the engineer collaborate to make sure the design isn't too hard to implement, but other than that the designer shouldn't care about whether developers are using Tailwind, StyleX, Sass, vanilla, or whatever.

I hardly expect a designer to take responsibility for something as transient and idiosyncratic as "oh, but this is hard in Tailwind."

I'm (not) surprised typographic scales are non-relevant for Tailwind developers
Tailwind itself is a design system. The authors actually put together a short book explaining their point of view on design systems (without referencing Tailwind) and I found it very difficult to argue with any of their points.

Then you look at Tailwind and realize it’s almost entirely that book packaged for others to use.

https://www.refactoringui.com/

The Tailwind library names grades of colors and sizes for you, but the book is ultimately about iterating design so that you can create your own design system. From the perspective of the book, the Tailwind defaults are inadequate as a design system.
But the Tailwind configuration provides a solid structure for your own though.
just like CSS
Not really the same, although I realize it can seem that way.

If you go low level enough everything technically fits that bill, it’s just a matter of how much work you have do to put the structure in place and what the burden is for other people to learn it.

It’s akin to raw Perl vs Ruby on Rails. You can do it that way, nothing is stopping you…but there are compelling reasons not to.

That's exactly the argument I'm making about Tailwind. Inadequate as a design system. You have these bundles of rules just a thin step above CSS and there's nothing obvious about how things should look.
No one cares what your typography ratio is if you can’t get it in front of a user quickly enough (dead code elimination), reliably enough (type safe), or cost effectively enough (i.e. if you have to pay for more developer time to implement the same work).

Tailwind is a tool for craftspeople, not artists. It democratises design by making it simpler. For folks that are really good designers, they should be happy that they can up their prices knowing that customers are paying for their expert eye, rather than just the basics again and again.

> Type safe typography ratio

Please explain how this is better than expressing typographic scales with CSS variables and calc()?

You're using a right angle bracket there like I said that. I didn't.

I would find it difficult to explain, especially given that this is exactly what Tailwind does: https://tailwindcss.com/docs/font-size.

> No one cares what your typography ratio is if you can’t get it in front of a user [...] reliably enough (type safe)

i mean it's not exactly what you said, but c'mon, that's obviously what they meant.

Ok fair enough. I was actually talking about the whole of Tailwind rather than just the typography ratios, but I can see how I could be understood in that way. My mistake. Either way, Tailwind works in exactly the way OP describes as their counter example.
Tailwind does not democratize design. Tailwind is generally 1:1 to CSS, sometimes 1:2 or 1:3. It's such a thin layer over CSS that you have to remember all the CSS. That does not make design easy or hard. You don't give people Tailwind and end up with design as beautiful as ShadCN, even though ShadCN in some perspective is just another wave of stereotypical startup design. The ability to go from blank button to beautiful Tailwind button is all on the author, not the fact that you're writing in a new lightweight inline syntax.

When I read the Tailwind book, my takeaway was their design philosophy was about the speed of iteration and how that interacts with designs whose parameters are too interdependent. Tailwind follows that philosophy by encouraging ad-hoc repeated edits over DRY. In that sense StyleX also fits the Tailwind philosophy very well even though StyleX is an even thinner layer over CSS.

I don’t really agree. You have curated colour palettes, so if you want a red, you’ve got red-50 to red-950, rather than an entire RGB colour space.

Similarly for font sizes, you don’t have to decide on a pixel size, just whether it’s small, large, extra large, etc. Border radii. Border widths. Padding.

There are lots of “sensible” defaults so you don’t have to pick even the units (should I use px or pt or em or rem or vw or ch or…) before we even talk about the numbers associated with those units.

(comment deleted)
You should really not do it like that,

--corporate-main-primary, secondary etc

Then map that to red-50 if you really want to.

but a design lives in cmyk/ral/rgb/hex not red-650

The go

--action-button-cta-hover etc that could map to corp primary or some other stuff

The Reactoring UI book would find whatever structure of defaults given to you as very inadequate for a design system. The book is about an iteration process for creating your own design system. The Tailwind library happens to empower that design process.

But by default there's basically no opinion on what even a button should look like or how colors should be used on your website. You have to create your own abstraction such as "brand-color" and "brand-primary". You have to create your own design system, as there is no Tailwind default button or anything.

If you talk about a default Tailwind look people might be confused and think of ShadCN.

Just because you can build great things with Tailwind doesn’t mean it’s not democratising design. In the same way as putting frets on a guitar helps amateur players make better music without stopping great players doing their thing, Tailwind is the “frets” on CSS that make sure your hands play the right notes. You can still get it wrong, and you can do inspired or uninspiring design with Tailwind, the same as any tool.
(comment deleted)
(comment deleted)
Man their very playground at https://play.tailwindcss.com/ gives this unreadable crap (sorry for swearing) for the very first `div` on the first line:

    relative grid min-h-screen grid-cols-[1fr_2.5rem_auto_2.5rem_1fr] grid-rows-[1fr_1px_auto_1px_1fr] bg-white [--pattern-fg:var(--color-gray-950)]/5 dark:bg-gray-950 dark:[--pattern-fg:var(--color-white)]/10

How can anyone prefer this gobbledygook over a nice CSS class declaration with line-separated standard CSS properties ? How can one even maintain this ?

Maybe the modern generation of web developers have IQ 200 and 20/20 vision with eidetic memory and I should just put myself to pasture.

Terrible take.

Take a guess at what “dark:bg-gray-950”, “bg-white” or “min-h-screen” means. You get them from context.

Imagine if you put a little bit of effort into learning Tailwind. You’d get the more complex declarations as well.

As to why it’s better than a class declaration, a lot has been written about using atomic, composable utility classes over reams of “write-once” class declarations.

I do not disagree that there are one or two recognizable elements in that encoded line-noise. Not sure what is the "terrible take" about it - if you take a poll, most would agree that it requires far too much eye-strain to read, far too much cognitive burden to parse, decode and mentally map to concepts.

Its like deciding to code your entire your app using regexes - all in long single lines without comments.

Because your not thinking of styles practically. You don't review style declarations, you review the rendered page/component. You see with your eyes that a component has the wrong border color, and AFTER THAT you go to your component code, find the border color declaration (if any), and update it/add it. Sometimes you'll even inspect the element in browser, and find the faulty class directly, making it even easier to target in code.

The Tailwind classes are "unreadable crap", that's true, but it's not a problem because you don't "read" it, no one does. You roughly parse it and edit it.

Personally I prefer how PandaCSS does it - similar end result with atomic css at compile time but it just lets you write your styles as readable objects instead of as insane strings.
Exactly, it's not like a novel where you are trying to read the entire thing. And it's an advantage because it is easier to parse. If I'm trying to change the color on that element, I have a very good idea what controls that. As opposed to something like "card_wrapper card_wrapper--striped". That certainly looks better, but if I'm just there to change the grid, now it's a more complicated change. In Tailwind, I can just look, see "grid-cols-[1fr_2.5rem_auto_2.5rem_1fr]" and know that not only that's where to change it, but that I can also change the classname there without worrying about a regression in some other element somewhere else. Whereas with "card_wrapper card_wrapper--striped", well what controls the grid? I have to look in another file, and I also have to be concerned about every other place those classes are used. (Or I have to add new one-off classnames, at which point the complaint about long classnames holds less weight.)
I just want the color palette of the Tailwind CSS.
Their palette is really neat. I always check it out when I need colour inspiration, especially for "cold greys" and other "state" colours (green for success, red for error, yellow for warning...).
yeah, the palette is neat. My main gripe with Tailwind is that it blends a set of design tokens (which I like) with a technology to apply them (which I don't like)
Maybe check out Open Props?

https://open-props.style/

I've seen that and it's a neat concept but unfortunately everything about that project looks hideous, so I'm not very keen on adopting it
Yes, someone should make a tailwind inspired bootstrap theme.
I actually did this for a former company that had a Bootstrap-based app - the designers started bugging that "we need to use Tailwind", and I couldn't figure out why they cared what tech we used.

In talking with them, realized they just were bored with our theme, ha. Not publicly accessible though, sorry. I should probably recreate this.

Radix Colors ?
I don't want to use React
I'm still a critic in terms of actually using it, but what I find amazing about tailwind is how amenable it is to AI-generated workflows. It seriously works _so good_. Anything can be expressed, and systematically. There's something amazingly useful there.
> what I find amazing about tailwind is how amenable it is to AI-generated workflows

It's highly amenable to human workflows as well. Of course, humans are more disparate than AIs so it doesn't suit all humans - no tool can. But it sure does seem like a majority of humans web developers like it.

So, I wonder how AI is going to work with the new upgrade. Are teams going to delay upgrading until there is proper Claude support, for example?
Should work well since there aren’t any removal of old features and classes.
Its horrible, annoying and gets in the way
(comment deleted)
Tailwind is mind-boggling to me. Like something that would be written by someone who doesn’t actually write a lot of HTML or CSS.

Bootstrap is bad enough, where you end up using 4, 5, 6 classes for display, margin, padding alterations to existing components.

It’s just unreadable crap. No wonder it’s popular though. Most people suck at designing. The ones that don’t aren’t using Tailwind.

>The ones that don’t aren’t using Tailwind.

True. And they're not using HTML or CSS either.

so much love for tailwind! I've used it since version 1 and have been always my default for starting new projects.

Congrats to tailwind team!

Last time I tried v4 the automatic content detection was pretty bad. It would falsely detect tailwind classes if it seen a similar name in a string in a code file. It seemed pretty dumb.
That is more or less how it worked in v3 already, because any string could be used as a CSS class.

"The way Tailwind scans your source code for classes is intentionally very simple — we don’t actually parse or execute any of your code in the language it’s written in, we just use regular expressions to extract every string that could possibly be a class name."

https://v3.tailwindcss.com/docs/content-configuration#class-...

The only difference in v4 is that scanning is so fast, they just scan roughly everything by default. You can still opt into manually specifying which files to scan.

https://tailwindcss.com/docs/detecting-classes-in-source-fil...

In v3, one can use `blocklist` in the config to eliminate false-positives, but with the config file gone, this seems no longer possible, so I won't be upgrading.

In one project, roughly 75% of the detections were false-positives, unnecessarily bloating the CSS.

Personally I'm not interested in using Tailwind but my main criticism is that it didn't go far enough in its approach.

Instead of using classes (which are extremely limiting) they should have created their own language like Imba did (inspired by TW).

https://imba.io/

Was it really necessary to break all existing apps using `npx @tailwindcss`?

It's an easy enough change to `npx @tailwindcss/cli` but we now have to go back and update all Apps and templates and since it uses v4 we now have to test every App to see if anything's broken with a v4 major release.

Given its massive install base, surprised they wouldn't maintain backward compatibility with v3 and have an explicit opt-in upgrade path to v4.

Edit:

v4 did actually break all our Tailwind Apps which doesn't support `@import "tailwindcss"`, likely because we use `npx tailwindcss` without any local npm dependencies. Trying to use the existing v3 `@tailwind components` renders a useless app.css. Only solution atm is to explicitly use v3 and change all our build scripts to use `npx tailwindcss@v3`.

You’re doing something silly living without a lock file to use a tool as part of your build process. Why don’t you actually include the version of the tool you want in your dev dependencies + lock file? That way, you don’t get broken. We’ve had the solution to this problem - lock files - for 15ish years, since Ruby’s `bundle` introduced it.
Not everything is a node App. We don't have a lock file because we don't have any local npm dependencies (as already mentioned). We're using `npx tailwindcss` as-is.
You clearly have a dependency on tailwindcss (if it can break you, you depend on it), and are using npm to fetch it (npx uses npm internally, they are installed together) so you can easily solve your problem by adding a couple json files with some version numbers in them. npx will pick up and use the version from your package.json, so no workflow change other than running `npm install …` once to generate package.json for your preferred semver specifier, and package-lock.json to guarantee your builds use a known-good version from now on.
FFS we don't have local dependencies. Which means we don't have any local node_modules and have never ran npm install (there are no dependencies to install!). There is no lock file or dependencies.

Our Apps don't have any npm dependencies nor needs to run npm install by design, we're not going to start now, as already stated we're switching to `tailwindcss@v3` instead.

The point is this was a documented supported use-case which all our non node.js Apps used, which have now broken as a result of this release.

I find it really hard to not immediately be reminded of this:

https://xkcd.com/1172/

We only use npm dependencies and bloated node_modules folders [1] if we absolutely have to and for our non node.js Apps we explicitly don't.

[1] https://www.reddit.com/r/ProgrammerHumor/comments/6s0wov/hea...

But why not though

I also use tailwindcss in a non-node project, but use npm package / lock files to easily lock javascript / css dependencies and make renovate able to update them for me.

I've linked to why. We prefer #NoBuild solutions where we'd only use local npm deps/node_modules if we absolutely have to, and for non JS Apps we don't.
The node_modules folder is still somewhere on your system (~/.npm/_npx probably?) containing the same tailwindcss dependency files, but if it helps you sleep easier at night it’s okay to pretend it doesn’t exist.
No kidding, I thought global tools worked with fairy cloud dust, now I wont be able to sleep! But knowing there's not a going to be a bloated node_modules folder and local dependencies running different versions unnecessarily maintained in every project will definitely help.
YOU DO have a local dependency.

Just add a mostly empty package.json like this:

    {
      "devDependencies": {
        "tailwindcss": "^3.4.17"
      }
    }
Run npm install once, and be done with it. You could even commit your node_modules if it helps.
We don't, we use npx to avoid needing any local dependencies.

`npx tailwind@v3` is the solution, definitely wont be committing node_modules to git, ever.

FWIW Tailwind can be used as a standalone executable.

This is how Phoenix/Elixir bundles Tailwind without requiring npm.

I don’t care how you do it, just make getting your dependencies deterministic based on files committed to your repo!

Happily the Tailwind hex package encourages you configure a fixed version number, so you’ll never get surprise breakage as long as you’re committing your mix.lock file as well.

I’m only suggesting package.json/package-lock.json because their projects are already using the npm ecosystem to fetch the tailwind dependency. A Makefile that does `curl $TAILWIND_GITHUB_RELEASE_URL -o ./departing/tailwind` is fine too (this is what Tailwind.hex is doing under the hood).

AFAIK using the tailwindcss-cli without npm makes it impossible to use Tailwind plugins, such as DaisyUI.
I believe that is true, although there is a project which bundles Tailwinds and DaisyUI into a single standalone executable:

https://github.com/dobicinaitis/tailwind-cli-extra

I have not tried this out yet, personally.

I just tried it... failed to load with very strange errors about postcss and unknown words.

FWIW, the tailwind binary from the official channel works great. I install it in my build.rs.

Shove an @ version in it
Yep `npx tailwindcss@v3` is the solution we ended up with. Just had to change this in all our Apps and project templates.
So why not npx tailwindcss@^3.0.0 (or whatever version was there when you started)?
> Given its massive install base, surprised they wouldn't maintain backward compatibility with v3 and have an explicit opt-in upgrade path to v4.

Given it's a major version change, I'd expect it to create breaking changes, otherwise it would be a minor version change.

Tailwind’s abuse of CSS classes as a DSL has always felt like a hack to me.

You shouldn’t need a special editor extension to get highlighting/autocomplete/etc, just use TypeScript and a CSS-in-TS solution.

> just use TypeScript and a CSS-in-TS solution

THIS is the definition of a hack to me, so yeah.

May be a hack but it just works.
To some extent, reading between the lines of many of these comments, I think “pure CSS” designers are feeling threatened by the quality level of Tailwind sites designed by the rest of us.
It's worse. React killed the craft of design engineering because everything is JavaScript. CSS develoeprs are gone.
Design engineers still exist, they just write more JS these days. They are still building UI and design systems and teaching craft & supporting full stack teams. The craft is there, but the tools are different.
True — they just need to be more engineers than designers.
I don’t think putting html in one file and css in another file makes you more or less of a designer than putting both html and css into a single file.
Switching from CSS based design systems to large TypeScript monoliths requires you to learn one or two things about engineering
I think the approach is different. Component style applications have to thing about all component presentation separately, web apps ressemble apps more than documents (d’uh) so it makes sense that they are designed as such.

Documents are designed holistically, you don’t care that much about how a thing (say, an image that is an aside) would look on the next page because on the next page there would be something completely different.

I think much of the debate and contention comes from the fact that many developers only worked on either web apps, or documents (e.g.: static blog, cms) and each try to convince the other group that their approach is the best.

My initial reaction to Tailwind was: what a pain. I already know CSS, now I have to learn CSS again...

I imagine its how parents might feel when they go to help their children with math homework only to find the math is now totally different from when they were in school and their methods (while still valid) for solving problems are no longer accepted by the school and their child is annoyed by having to reconcile the two systems...

I get the, tailwind works well in a team and scales nicely and you just have to use it, mentality. I've experienced it.

I still prefer a plain style sheets that targets elements by a class or tag (especially since CSS supports nested selectors!).

There is an issue in managing stylesheets, and for that I really like how Remix/React Router manages CSS where CSS flies are defined and applied at the route level. Where that isn't enough or dynamic styles are too complex for a .css file:

    style={{...}}
is always available.

CSS is so powerful, flexible, and extensible, tailwind feels like a limitation rather than an enhancement. I don't understand the continued appeal, but clearly many others do. I'm not sure why, but I am confident we'll all have moved on to something else in another 3 or 4 years too.

Limitation reduces available complexity and that’s why tailwind wins. It’s a composable, standardized, and modularized wrapper around a very massive and complex system. That’s a big advancement.
I agree it’s frustrating initially to re-learn CSS… I used to make the same arguments. But after contributing to an open-source project using Tailwind I got up to speed, and now I feel differently.

Tailwind is essentially just stenography for style={{…}} - a single utility takes 15 characters that would take multiple lines in a .css file or style object. It greatly reduces the amount of time I need to spend googling stuff like “visual text replacement css” or perusing various css cheat sheets or skimming through css-tricks blog posts from 8 years ago. Instead I always go to tailwind docs, and quickly learn the utility class that just does the thing I want. A surprising amount of it fits in my brain cache, much more than trying to cache the css for all the tasks I might need to do in a layout.

I think it’s because now your entire component is contained in a single file. No more separately messing around with CSS. The styles are right there on the element they apply to without having to cross reference anything.

You could do this with just the css attribute, but that has the issue that everyone has always been taught it is wrong to do that, and a list of strings that contain a bunch of utility is easier than writing those plain CSS objects.

> You could do this with just the css attribute, but that has the issue that everyone has always been taught it is wrong to do that

But why is it wrong to use the style attribute? What makes using tailwind to do the same thing "not wrong"?

Also this https://tailwindcss.com/docs/hover-focus-and-other-states#us... and https://tailwindcss.com/docs/hover-focus-and-other-states#st... look like reinventing the Cascading of CSS with an awful syntax.

I think it's also about automatically purging and slimming down your CSS, which is easier to do when you're just comparing tokens.

Although nowadays I'm sure they could technically do the same thing with the built in parsers without having to rely on just simple tokens.

> But why is it wrong to use the style attribute? What makes using tailwind to do the same thing "not wrong"?

The time people were taught it was wrong is thr time when all your elements were rendered on the server and the style was duplicated for every component it applied to.

Client rendered JS only sends it over the wire once and then duplicates it on the client.

Tailwind only allows a few options, so it’s less likely you have slightly different styles everywhere.

I think the awful syntax you talk about is really nice, since it covers 99% of everything I ever need to do with it. The cascading part of CSS is really cool, but 99% of the time it’s confusing when I don’t need it.

Tailwind I use for hobby projects but we’re still sticking with style={{…}} at Notion. Since the app launched there’s been many generations of CSS-for-React (Airbnb Aphrodite era, styled-components/Emotion era, styled-jsx/linaria era, CSS modules era, Tailwind era) come up, get hype, and then thrown in the trash heap. Probably the best move for us would be an optimizing compiler for style={{…}} or our useStyles hook.
I'm learning math with my kid and it's not different to what I learned. Can still solve everything quickly.

On the other hand there are those posts on social media mixing multiplication and division and telling you there is only one true answer to those. Tailwind isn't that bad, but it's more into this direction for me as an old fart ;)

In the US you can get all the right answers on a test and still fail
I like tailwind but think it’s not needed anymore as CSS got better. Utility frameworks don’t necessarily need a build step.

I forked and finished Tachyons successor Tachyons 5: It has container queries built in and p3 colors.

https://github.com/gobijan/tachyons5/blob/main/tachyons5.css

If you need very sophisticated layouts write them in plain css. For quick styling utilities are awesome.

Unpopular opinion. Now downvote me to the ground.

Text of TFA is cropped on my Safari (iPhone 7), a bit ironic init?
Question for those developers who, like me, have no f/end build step: How would I use tailwind without a f/end build step? All the examples of using tailwind 4.0 on the linked site assume a f/end build step.

My project does not use (and I have no plans to include) npm, or PostCSS, etc.

For a static site I have, I manually run the Tailwind tool when I include new classes. It generates style css and I commit this file to git.
This is what keeps me from using Tailwind too. I simply do not want to add the maintenance headaches of an npm-based build process to my project.
> I simply do not want to add the maintenance headaches of an npm-based build process to my project.

Apparently I was just too blind to find it - here is how you can (presumably) use tailwind without pulling in npm and node.js.

https://tailwindcss.com/blog/standalone-cli

Vite dev, preview and build scripts make it so stupidly simple that I can’t believe people don’t pull it for all, including the simplest, sites.

Plus I couldn’t imagine developing without TypeScript and hot reloads in 2025.

I'm pretty sure the point of using TailwindCSS is to use build step. There is another way, it uses Tailwind's CDN. But I think even the developer don't recommend it outside of development phase

If you don't want to use NPM, I can recommend Tailwind's standalone CLI

> If you don't want to use NPM, I can recommend Tailwind's standalone CLI

Didn't know there was one. Will look into it.