Hacker News new | past | comments | ask | show | jobs | submit login
Open-sourcing our progress on Tailwind CSS v4.0 (tailwindcss.com)
190 points by ssernikk 9 months ago | hide | past | favorite | 164 comments



Tailwind is the second best thing ever happend to frontend, only Vue 3 tops it.

Not having to come up with names for CSS classes, no duplicated CSS code, no fighting conflicting classes, everything in one file, being able to visualize a component just by reading the code... it's a godsend. I'll never go back to SCSS unless work obliges me.

Vue 3 with <script setup lang="ts">, TailwindCSS and Vite. The way God intended.


The first time I saw tailwind I almost threw up in my mouth because it broke so much I hold dear about CSS. A few weeks later I went to their site being all wtf is going on here, and I saw this quote on the front page from its creator:

> If you can suppress the urge to retch long enough to give it a chance, I really think you’ll wonder how you ever worked with CSS any other way.

Now I'm going to try it.


Please do try it, it really does speed things up if you care enough to learn it. IDE integration is a must. A lot of people seem to try it for five minutes, then conclude with absolute certainty that “this sucks” which is very annoying. If you like building good web views fast but don’t care enough to learn the massive core of css (or some hot new js-to-css-or-whatever tool) then tailwindcss is perfect. I build web views every now and then, but it’s not interesting to me, I want to rabbit hole on the real issues, which usually reside elsewhere. Also, I learned it years ago, and that knowledge is still useful, can’t say that about most web tech :)


I hated Tailwind for the first week I used it, and couldn’t imagine working without it by week two.


I’ve tried it - I’m just too used to working with Bootstrap.


They're different things IMHO.

Bootstrap gives you a pre-made look and feel that you can use despite knowing CSS or not and maybe you can customize a bit, make a theme, etc. Bootstrap is more like "Tailwind UI" which is different thing from Tailwind (the tool).

To use plain Tailwind (without Tailwind UI) you do need to know CSS. It's just like a "CSS-in-JS" tool, except it's "CSS-in-HTML" this time.


I was one of those who resisted. Now I won't not use tailwind if I have a choice. The best thing about it is I feel like I'm still writing vanilla CSS, just in a different way.


I think it's been the same situation with React. Everyone hated JSX when it first came out, then people realized the benefits outweigh the drawbacks.


Similar feelings.

It goes against semantic web, the old css zen garden etc, with good markup I can style a page however I want.

However using tailwind, it’s the get shit done tool. It is ugly, it goes against good web design and everything I believe makes good web design but it works fantastically well in practice.

I dislike using tailwind, at the same time I will choose to use tailwind without hesitation as it makes up process a lot less friction and avoids selector conflicts.


> Not having to come up with names for CSS classes

As soon as you want theming you'll need to start naming stuff. And if you want that theming to support third-party CSS overrides, or need good CSS selector support, you're going to be back to needing to name classes again.

Not everyone needs that, and that's fine. But there are plenty of people working on products and in environments where the Tailwind way is not going to be the path of least friction.

I would actually say StoryBook, or the StoryBook pattern at least, has been a much greater boon on FE development over the last decade.


A nice thing about tw is you can set your colors, paddings, etc, to resolve to CSS variables. That + some tweaks to the tailwind config, you get a nice themeable setup that doesn’t deviate too far from vanilla tailwind, imo.


Somewhat - but when your theme change does things like "buttons are now green outlined rectangles instead of blue filled rounded corners", Tailwind shows its weaknesses.

DaisyUI on top of Tailwind helps, but then you may as well use Bootstrap and get better component support.


Coming up with css class names is not hard. And if you're that creatively inhibited to not come up with the class name 'pricing-card' for cards in the pricing table, there's crutches like BEM ( https://getbem.com/introduction/ )


BEM was great, for the early to mid 2010s. Utility classes have still been a big productivity win for me.

Working on an app with a great deal of technical debt last year, moving to Tailwind made a world of difference in being able to restyle components without also breaking styles on distant parts of the app that nobody on the team realized were relying on the same styles.


Utility classes are good and all. Scoped css is great.

"Naming things is hard" is still such a cop-out.


You can still name things when it makes sense, I just like that in tailwind I don't have to name ALL of the things. It's nice to be able to easily add some margin, or padding, or a few style properties to an element, instead of coming up with a name AND adding those properties in a separate file.


“Naming things” being one of the two / three hard problems in software development is literally a meme. They didn’t pull it out of thin air.


You could say the same about style="" attribute and !important

Mess is still mess even if you are making it through a framework.


It's not exactly easy either.

In the end I'll be writing <PricingCard :price="product.price" /> anyway. All that Tailwind garbage will be nicely hidden inside the component.


That's fine. Saying it's redundant is 100% valid. That's not what the OP said.

Saying it's because naming a class is hard is BS.



I need to bookmark that link, it's perfect.


And in practical real life terms (where teams and long term projects and people coming and leaving the team over years and different skill levels, etc) is how CSS becomes a write-only mess.

Tailwind is primarily a way to do "css-in-js", except it's "css-in-html". It might not look nice on the eye but it's fucking easier to maintain, safer to remove, etc. As long as you have a way to create "components" you're fine.

> Coming up with css class names is not hard.

Yes, unless you work alone on your tiny 2 weeks old side project, it's fucking hard.


Have you tried Svelte?


It's slightly more convenient, but Vue3 is already great. I like to support an ecosystem and I want a framework to keep existing, making sure I can maintain my projects in the future. That is why I don't jump ship.


I have, it's just as good if not a tad better, but I'm so comfortable and productive with Vue and they're so similar that it's just not worth switching. I'm also very familiar with the Vue ecosystem, so anytime I need a library or plugin I know exactly what to pull.


Nothing against you, but I swear Svelte is Rust of frontend tech. Whatever the topic, it always pops up out of nowhere.

idiot edit: not React, Rust.


Svelte pops up out of nowhere because people tend to really love it. Not sure how it's the "React of frontend tech" since React is a competing frontend framework (which is now moving to adopt a Svelte-like compiled approach).

I haven't used Vue (any version) so this wouldn't be the place I'd normally chime in about Svelte. People seem to love Vue as well.


> React is a competing frontend framework (which is now moving to adopt a Svelte-like compiled approach)

React has been moving in the direction of a compiled approach for over seven years now[1], predating Svelte’s first release. The introduction of hooks in 2018 grew out of early efforts on an optimizing compiler. Those earlier efforts were hampered by class semantics making things like constant folding across components difficult. React Forget seems like a predictable progression from there.

[1] https://github.com/facebook/react/issues/7323


I'm an idiot. I meant Rust :) Where people are enamored with tech enough to evangelize whenever and wherever they can on their own.


Interesting take. I get why people writing a certain class of programs love Rust, but I can assure you Svelte doesn't do much to ensure correctness of the front-end app. It's just way more ergonomic than React for the vast majority of small to mid-size projects, and probably large projects too.

Rust is also about 100X as difficult to learn as Svelte (assuming you have basic familiarity with front-end dev), and easier to learn than React as well. Speaking from personal experience.


You are discussing attributes of Rust that GP did not intend to compare with Vue. They are talking about the evangelistic user base.


That, but also because you interpreted a question to be a form of generalization.

The great thing about HN is you can easily see a users comments.


>which is now moving to adopt a Svelte-like compiled approach

Interesting. Is there a page where I can read more about this and the current progress?



Too bad the buttons come out with transparent background. I gave up and used boostrap 5, since I had to actually get work done instead of reading github issues.


What? It doesn’t sound like you actually looked at the premise of Tailwind in the first place. It does not come with pre-canned components. This is clearly user error.


Sure. The "solution" is to disable preflight or override its styles. Also, this happened on a from scratch codebase without any funny css.

https://github.com/tailwindlabs/tailwindcss/issues/6602


In all fairness you are comparing a framework vs no framework. I'd for sure take TW over nothing, but there are other frameworks too.


God then came forth yet again and blest us with Svelte. The devil then appeared and introduced runes


Maybe we should start to treat this like the yearly hardware releases? Buy one generation, skip the next, buy the next...

So if you're on the vue-wagon, skip svelte and wait until the next "The way God intended". If you're on svelte now, skip the next "The way God intended" and then after that, jump on the new wagon.


That was kind of my story lol

I was heavily into full-stack SSR frameworks + jQuery, then Angular and React came along and I was like "oh heaven, is this were we headed?", ignored both of those for years and finally found peace in the sacred words of Evan You.


Typescript + direct DOM manipulation + HTML + CSS 4 lyfe! Fight me.

Helper functions like createEl(tag, attributes, style, text) help...


TypeScript is my "skip X" phase, I'll wait for the next compile-to-js language which better be a dynamic one again. Hopefully something in the lisp direction instead of the opposite like TypeScript. JavaScript deserves to be free of its shackles.


ClojureScript has entered the chat...


Yeah, something like that, but written from the ground up with closer JavaScript interop and made for writing UIs :)


Has Hackernews really devolved into this dogmatic nonsense?


Yep. I like Tailwind, one can list the benefits and say he likes it but GP's comment surely could be less full of zealotry.


As a forceful critic of Tailwind over many years now, I must say all of the announcements under the CSS-first configuration are extremely welcome. This makes it possible to take advantage of all of Tailwind's design tokens, reset, etc.—and even even customize them via real CSS—and then use tokens in honest-to-goodness CSS via native variables. This opens up a new world of "light" usage of Tailwind for its theming and utilities, *without* throwing away all of the awesomeness of modern CSS architecture, the cascade, and even shadow DOM in web components.

I'm a huge fan of this major improvement to the framework.


CTRL+u gives a nice example of the syntax.

For example to make a box with rounded corners and a top and bottom section, all you need is this intuitive one-liner:

<div class="mt-5 mb-8 first:mt-0 last:mb-0 relative overflow-hidden rounded-2xl"><div class="pt-2 bg-slate-800 shadow-lg group"><div class="flex text-slate-400 text-xs leading-6"><div class="flex-none text-sky-300 border-t border-b border-t-transparent border-b-sky-300 px-4 py-1 flex items-center">app.css</div><div class="flex-auto flex items-center bg-slate-700/50 border border-slate-500/30 rounded-tl"></div></div><div class="children:my-0 children:!shadow-none children:bg-transparent"><pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@import</span> <span class="token string">"tailwindcss"</span><span class="token punctuation">;</span></span></code></pre></div></div><div class="pointer-events-none absolute inset-0 rounded-2xl dark:ring-1 dark:ring-white/10 dark:ring-inset" aria-hidden="true"></div></div>


A box with rounded corners and a top and bottom section:

  <div class="bg-white rounded-2xl">
    <div class="bg-blue-500">Top Section</div>
    <div>Bottom Section</div>
  </div>


A few issues here:

1. When you're working with this code, it's far easier to read with proper formatting and syntax highlighting. I know people take issue with the verbosity of tailwind, but anything will look awful if you remove formatting.

2. This is lacking an equivalent non-tailwind approach. If you can share the equivalent vanilla HTML/CSS (or pick your preferred framework), and then paste it here as an unformatted text blob, this might be a bit more fair.

3. I don't think it's fair to describe this as just a "box with rounded corners and a top and bottom section". That can be done with tailwind with less complexity/syntax, if that's truly all you want.


Here is an example from their own website. It's for a very simple interface. Do you think this looks maintainable?

    <main class="py-6 px-4 sm:p-6 md:py-10 md:px-8">
      <div class="max-w-4xl mx-auto grid grid-cols-1 lg:max-w-5xl lg:gap-x-20 lg:grid-cols-2">
        <div class="relative p-3 col-start-1 row-start-1 flex flex-col-reverse rounded-lg bg-gradient-to-t from-black/75 via-black/0 sm:bg-none sm:row-start-2 sm:p-0 lg:row-start-1">
          <h1 class="mt-1 text-lg font-semibold text-white sm:text-slate-900 md:text-2xl dark:sm:text-white">Beach House in Collingwood</h1>
          <p class="text-sm leading-4 font-medium text-white sm:text-slate-500 dark:sm:text-slate-400">Entire house</p>
        </div>
        <div class="grid gap-4 col-start-1 col-end-3 row-start-1 sm:mb-6 sm:grid-cols-4 lg:gap-6 lg:col-start-2 lg:row-end-6 lg:row-span-6 lg:mb-0">
          <img src="/beach-house.jpg" alt="" class="w-full h-60 object-cover rounded-lg sm:h-52 sm:col-span-2 lg:col-span-full" loading="lazy">
          <img src="/beach-house-interior-1.jpg" alt="" class="hidden w-full h-52 object-cover rounded-lg sm:block sm:col-span-2 md:col-span-1 lg:row-start-2 lg:col-span-2 lg:h-32" loading="lazy">
          <img src="/beach-house-interior-2.jpg" alt="" class="hidden w-full h-52 object-cover rounded-lg md:block lg:row-start-2 lg:col-span-2 lg:h-32" loading="lazy">
        </div>
        <dl class="mt-4 text-xs font-medium flex items-center row-start-2 sm:mt-1 sm:row-start-3 md:mt-2.5 lg:row-start-2">
          <dt class="sr-only">Reviews</dt>
          <dd class="text-indigo-600 flex items-center dark:text-indigo-400">
            <svg width="24" height="24" fill="none" aria-hidden="true" class="mr-1 stroke-current dark:stroke-indigo-500">
              <path d="m12 5 2 5h5l-4 4 2.103 5L12 16l-5.103 3L9 14l-4-4h5l2-5Z"  stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
            </svg>
            <span>4.89 <span class="text-slate-400 font-normal">(128)</span></span>
          </dd>
          <dt class="sr-only">Location</dt>
          <dd class="flex items-center">
            <svg width="2" height="2" aria-hidden="true" fill="currentColor" class="mx-3 text-slate-300">
              <circle cx="1" cy="1" r="1" />
            </svg>
            <svg width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1 text-slate-400 dark:text-slate-500" aria-hidden="true">
              <path d="M18 11.034C18 14.897 12 19 12 19s-6-4.103-6-7.966C6 7.655 8.819 5 12 5s6 2.655 6 6.034Z" />
              <path d="M14 11a2 2 0 1 1-4 0 2 2 0 0 1 4 0Z" />
            </svg>
            Collingwood, Ontario
          </dd>
        </dl>
        <div class="mt-4 col-start-1 row-start-3 self-center sm:mt-0 sm:col-start-2 sm:row-start-2 sm:row-span-2 lg:mt-6 lg:col-start-1 lg:row-start-3 lg:row-end-4">
          <button type="button" class="bg-indigo-600 text-white text-sm leading-6 font-medium py-2 px-3 rounded-lg">Check availability</button>
        </div>
        <p class="mt-4 text-sm leading-6 col-start-1 sm:col-span-2 lg:mt-6 lg:row-start-4 lg:col-span-1 dark:text-slate-400">
          This sunny and spacious room is for those traveling light and looking for a comfy and cosy place to lay their head for a night or two. This beach house sits in a vibrant neighborhood littered with cafes, pubs, restaurants and supermarkets and is close to all the major attractions such as Edinburgh Castle and Arthur's Seat.
        </p>
      </div>
    </main>


> Do you think this looks maintainable?

I guess that depends. Compared to what?

Again, show me the equivalent widget implemented some other way and we can have a useful discussion.

Having spent a little time experimenting with tailwind for prototypes in the past, I can understand what that snippet is doing pretty easily. Having spent a lot more time writing vanilla HTML/CSS, I can immediately imagine all of the ways the vanilla version would be a nightmare, or at least take far longer to build “properly”.

Tailwind is a fascinating project because it seems to either make sense to people or it seems to deeply offend them. For whatever reason, I’m able to build things with tailwind after just a few hours of use that I could never accomplish from scratch (or with some popular CSS frameworks for that matter) after years of hacking on HTML/CSS.

15 minutes getting familiar with the class naming conventions makes all of this seem far less scary.

And it’s worth considering the variety of use cases a framework like this is useful for. Maintainability means very different things depending on context, team, and what kind of thing you’re building.


I can't wait to see what happens in 5 years when all of this unmaintainable mess still needs maintaining. I suspect it'll be just as fun as maintaining old bootstrap or any other short-lived frameworks of yester years.

Inline styles and abusing divs. I suspect the next hotness will be nested tables again.


Right? I can't believe this is being so overwhelmingly used all of a sudden.


This is only 20 max CSS classes. Yah, you haven't been a REAL tailwind maintainer if you haven't worked on a website that uses 50+ CSS classes for elements - some with minor variants! I had to do so and deeply regret the experience.

It was like extreme eye exercise with eyeballs popping out at the end of the work day.

Tailwind CSS is a write-only CSS cult at the moment. Cults take some time to die. After a decade, one will have dozens of "Why I quit using Tailwind" posts on HN. Back to vanilla CSS!

Now, if one wants to use a sane implementation of Atomic CSS, look at: https://open-props.style/. Jeez that is so much more readable and maintainable.


Yes. Much more than doing this via a number of detached and separate CSS classes defined in different files, with colliding rules and all the fun that goes with this. Or better yet, inventing enough small composable utility functions to work around these issues until you might have well have used tailwind.

When you say “does this look maintainable”, what you should be saying is “does this look maintainable compared to this other thing”.


I’d love to make a simple html skeleton and basic css rules to show a comparison but I don’t have the time.


> but I don’t have the time

And this, to me, is why Tailwind is so popular and why I find it valuable. Despite looking a bit verbose at first, it’s pretty easy to pull together some pretty advanced pages without having to invest much time at all.

And the time saved only increases with more proficiency/familiarity with the available classes.

Things very quickly “just work”, and the conventions apply pretty uniformly.


It would probably take me 20 minutes or so, and would be very maintainable and not make anyone's eyes bleed. I'm not willing to put that 20 mins in to prove my point, but I am certain that the unmaintainable code vomit which they have as an example on their website took much longer than that.


You’d need to build a site with multiple pages, with multiple developers and lots of concurrent changes.

Then you’d realise why people don’t use raw CSS


I use raw CSS. I just scope it to the component level and I've never had a problem on any of the projects I've worked on. I do tend to avoid absolutely massive projects but I've worked on plenty of fairly big codebases and there is no problem as long as the CSS is scoped well using CSS modules. Inline styles are awful for maintainability and readability of the html, which is an important semantic description of your content.


I host a secret dislike for it but was really turned off by you including in-lined SVG files, shifted me more towards "maybe it isn't bad relative to peers"


That's what they have on their homepage, should I have removed it? Does this look any more maintainable?

    <main class="py-6 px-4 sm:p-6 md:py-10 md:px-8">
      <div class="max-w-4xl mx-auto grid grid-cols-1 lg:max-w-5xl lg:gap-x-20 lg:grid-cols-2">
        <div class="relative p-3 col-start-1 row-start-1 flex flex-col-reverse rounded-lg bg-gradient-to-t from-black/75 via-black/0 sm:bg-none sm:row-start-2 sm:p-0 lg:row-start-1">
          <h1 class="mt-1 text-lg font-semibold text-white sm:text-slate-900 md:text-2xl dark:sm:text-white">Beach House in Collingwood</h1>
          <p class="text-sm leading-4 font-medium text-white sm:text-slate-500 dark:sm:text-slate-400">Entire house</p>
        </div>
        <div class="grid gap-4 col-start-1 col-end-3 row-start-1 sm:mb-6 sm:grid-cols-4 lg:gap-6 lg:col-start-2 lg:row-end-6 lg:row-span-6 lg:mb-0">
          <img src="/beach-house.jpg" alt="" class="w-full h-60 object-cover rounded-lg sm:h-52 sm:col-span-2 lg:col-span-full" loading="lazy">
          <img src="/beach-house-interior-1.jpg" alt="" class="hidden w-full h-52 object-cover rounded-lg sm:block sm:col-span-2 md:col-span-1 lg:row-start-2 lg:col-span-2 lg:h-32" loading="lazy">
          <img src="/beach-house-interior-2.jpg" alt="" class="hidden w-full h-52 object-cover rounded-lg md:block lg:row-start-2 lg:col-span-2 lg:h-32" loading="lazy">
        </div>
        <dl class="mt-4 text-xs font-medium flex items-center row-start-2 sm:mt-1 sm:row-start-3 md:mt-2.5 lg:row-start-2">
          <dt class="sr-only">Reviews</dt>
          <dd class="text-indigo-600 flex items-center dark:text-indigo-400">
            <SVG GOES HERE>
            <span>4.89 <span class="text-slate-400 font-normal">(128)</span></span>
          </dd>
          <dt class="sr-only">Location</dt>
          <dd class="flex items-center">
            <SVG GOES HERE>
            Collingwood, Ontario
          </dd>
        </dl>
        <div class="mt-4 col-start-1 row-start-3 self-center sm:mt-0 sm:col-start-2 sm:row-start-2 sm:row-span-2 lg:mt-6 lg:col-start-1 lg:row-start-3 lg:row-end-4">
          <button type="button" class="bg-indigo-600 text-white text-sm leading-6 font-medium py-2 px-3 rounded-lg">Check availability</button>
        </div>
        <p class="mt-4 text-sm leading-6 col-start-1 sm:col-span-2 lg:mt-6 lg:row-start-4 lg:col-span-1 dark:text-slate-400">
          This sunny and spacious room is for those traveling light and looking for a comfy and cosy place to lay their head for a night or two. This beach house sits in a vibrant neighborhood littered with cafes, pubs, restaurants and supermarkets and is close to all the major attractions such as Edinburgh Castle and Arthur's Seat.
        </p>
      </div>
    </main>


Here's an excerpt from YouTubes Javascript. Do you think this looks maintainable?

    Z3 = function(a) { a = g.fb(a); delete X3[a]; g.md(X3) && Y3 && Y3.stop() },
...or maybe the build-output isn't a great indicator for maintainability. If you write your html directly like you posted above, it won't be maintainable regardless of how you structure your css.


What I posted isn’t build output, it’s the example they give on the homepage of their website.


That's super funny that even a defender of tailwind mistook source code for build output.


Okay, if that's how they're selling Tailwind, I can understand why some developers are confused.

I assume they do it because they don't want to promote a specific framework on their homepage.

Go to the section "Worried about duplication? Don’t be." Does the code there look more maintainable to you? Because that's how you should be writing any moderately complex html anyways.


It's not meant to be maintained. If you want to make changes, start over.

/s?


I'll take this over grepping hundreds CSS files trying to find that one specific class and hoping it's not used anywhere else anyday of the week.


Yes. The best explanation of Tailwind is when Adam describes it as “an API for your design system.”

The biggest problem with CSS when trying to maintain a design system is the same problems you run into any time you use inheritance in programming.

Inheritance has its place, but making your CSS composable the way Tailwind does makes it practical to actually adhere to a design system.

If you’re more worried about the purity of your HTML, then Tailwind is not for you.


If you have to use grep to find a CSS class, you're doing it very wrong. Not having any discipline or organizational skills leads to needing grep to find CSS, it is not something inherent to CSS itself.

In my front end, for example, I have registration-page.jsx and registration-page.less, and there is really zero mystery where the styles are for the registration-page. It uses components like password-input.jsx, and guess what? the CSS for that is in password-input.less. There's no grepping, there's no difficulty finding the classes that are specified. Everything is very orderly and easy to find.


Even if your styles aren't colocated you can use sourcemapping alongside established patterns on how to structure out your scss/less. Just inspect the element and click on the filename next to your selector and it opens in your editor.


And what about projects that don’t exist in a paradigm where css can be collocated with templates/components? Legacy projects? Large contributor teams?


Can you not keep your files in some sort of order?


On my pet projects? Absolutely.

On work projects with 5 years of contributions wrote by 50+ collaborators and close deadlines? Hardly think so.


grep -R .class-name ./assets/css/wherever

Or use your IDE's project search? In vscode you can just ctrl-click on the class and it should find it?

IT IS NOT DIFFICULT


Until you discover that one feature in production that is built with dynamically concatenated class names and the SCSS file is deeply nested to hell and back so your search didn’t find `card__${cardType}__inner—-${userPrefColor}-background`

Ask me how I know!


That doesn't sound like something any tooling should be supporting.

I've done that before, and everyone who does regrets it. It should be a linting error, not something we need to re-write searching to support.


What do you honestly expect someone to reply to this comment?

Yes, and?

Developers tend to do bad things sometimes. It happens. That’s the reality.


Sourcemaps and the browser inspector will tell you exactly where the styling for that element is coming from


Why use a bad faith interpretation of what Tailwind is? You know this isn't what it looks like when you are developing


For fun I tried to make an equivalently bad-faith two-liner with vanilla HTML+CSS that preserves the Tailwind behavior:

<div class="custom-box"><div class="header"><div class="tab">app.css</div><div class="header-expand"></div></div><div class="content"><pre><code>@import "tailwindcss";</code></pre></div></div>

.custom-box {margin-top: 1.25rem; margin-bottom: 2rem; position: relative; overflow: hidden; border-radius: 0.5rem;}.custom-box:first-child {margin-top: 0;}.custom-box:last-child {margin-bottom: 0;}.header {padding-top: 0.5rem; background-color: #1E293B; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); display: flex; color: #94A3B8; font-size: 0.75rem; line-height: 1.5;}.tab {flex: none; color: #0EA5E9; border-top: transparent; border-bottom: 2px solid #0EA5E9; padding: 0.25rem 1rem; display: flex; align-items: center;}.header-expand {flex-grow: 1; background-color: #334155/50; border: 1px solid rgba(156, 163, 175, 0.3); border-radius: 0.375rem 0 0 0;}.content pre, .content code {margin: 0; background: none; box-shadow: none;}@media (prefers-color-scheme: dark) {.custom-box::after {box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);}.header {background-color: #334155;}.tab {color: #bfdbfe;}.header-expand {background-color: #475569; border-color: rgba(255, 255, 255, 0.2);}}@media (min-width: 640px) {.custom-box {margin-top: 1.5rem; margin-bottom: 2.5rem;}.header {padding-top: 0.75rem;}.tab, .header-expand {padding: 0.5rem 1.25rem;}.content pre, .content code {font-size: 0.875rem;}}@media (min-width: 768px) {.custom-box {margin-top: 2rem; margin-bottom: 3rem;}.header {padding-top: 1rem;}.tab, .header-expand {padding: 0.75rem 1.5rem;}.content pre, .content code {font-size: 1rem;}}@media (min-width: 1024px) {.custom-box {margin-top: 2.5rem; margin-bottom: 3.5rem;}.header {padding-top: 1.25rem;}.tab, .header-expand {padding: 1rem 1.75rem;}.content pre, .content code {font-size: 1.125rem;}}@media (min-width: 1280px) {.custom-box {margin-top: 3rem; margin-bottom: 4rem;}.header {padding-top: 1.5rem;}.tab, .header-expand {padding: 1.25rem 2rem;}.content pre, .content code {font-size: 1.25rem;}}@media (min-width: 1536px) {.custom-box {margin-top: 3.5rem; margin-bottom: 4.5rem;}.header {padding-top: 1.75rem;}.tab, .header-expand {padding: 1.5rem 2.25rem;}.content pre, .content code {font-size: 1.375rem;}}.content > * {margin:0; box-shadow: none; background: transparent;}

(this probably an incomplete/buggy/incorrect port of Tailwind behavior)


I'll take this version over tailwind anytime. It's one auto-formatting step from being perfectly readable for someone who knows css and styles tell me how it looks like and css classes tells me WHAT IT IS. And information (nearly?) completely missing from tailwind counterpart. I can also easily see what structure the DOM has.


> ...tells me WHAT IT IS.

Tailwind is a styling library, not label system. You want to know what something is? use the id attribute, it's not rocket science

> I can also easily see what structure the DOM has.

Really? Because even in the cherry-picked half-assed example above I can more easily read the DOM structure than whatever this is.


> Tailwind is a styling library, not label system.

So what is it doing in my html tags?

It's not a place for styling since css was invented.

> ... than whatever this is.

Whatever this is? These are 7 html tags and I can see how nested they are in 10 seconds even without autoformatting.

<div class="custom-box"><div class="header"><div class="tab">app.css</div><div class="header-expand"></div></div><div class="content"><pre><code>@import "tailwindcss";</code></pre></div></div>

In tailwind example you need more than 30 seconds to even count them.


Oh no! This is unreadable and unmaintainable.


yeah it just looks like that to everyone else, so you're avoiding the pain yourself while inflicting it upon anyone interested in inspecting the compiled output


I'm not a fan of tailwind, but this isn't what I optimise for when building websites.

Besides, I suspect (but not know, because my experience with tailwind is very minimal) that that output is readable and understandable by those experienced and developing with tailwind. On top of all the other affordances modern dev tools gives to understand styling on elements (esp. the computed pane)


When you build websites you are creating code for others to read as much as you're creating an "app" or document.

It's the very essence of what's good and special about the web. If the companies that are trying to do away with this succeed, we will have lost something important.

The web is and should remain de facto open source.


> When you build websites you are creating code for others to read as much as you're creating an "app" or document.

I couldn't disagree any more with this. When the overwhelming majority of your users would never actually be impacted by this, I believe you have more of a responsibility to the bulk of your users, rather than a fraction of a percentage.

I say this as an open-source developer, who ships source maps to production. I would much rather us increase our development veloticity and build higher quality products rather than satisfy one nerd who might want to occasionally view source.


Bloat is detrimental to the bulk of your users.


> When you build websites you are creating code for others to read as much as you're creating an "app" or document.

That's an approach people are certainly welcome to take, and I'm glad that some people do, but I disagree that this is what the act of building a website entails.

This feels a bit like romanticizing the early days of the web, when the primary form of learning involved reading other people's source code. The depth and breadth of ways to learn in 2024 looks nothing like those early days.

If I choose to build something to solve a particular need or to communicate something I care about, it's my choice as to how I do that.

> It's the very essence of what's good and special about the web.

The very essence of what's good and special about the web is the diversity of solutions, the myriad of entry points to becoming a web developer, the existence of tools ranging from vanilla HTML/CSS all the way up to complex frameworks like Tailwind, and your freedom to pick your path.

Tailwind's existence does not threaten the layers underneath it.


I work on a "white label" site that gets customized by an army of css coders/designers. Tailwind seems like it would be a total non-starter for us.


Your use case is fairly specific. Tailwind is a tool, if it doesn't make sense to you and your use case, it's okay to not use it. That said, it's not okay to misrepresent what Tailwind actually is like the original commenter did.


Who would be interested in inspecting the compiled code? Genuine question.


I'm so glad this wasn't the prevailing opinion when they first came up with the web. "Inspect source" is how I learned how to build my first website in the newly released browser called "Firefox 1.0".


I learned how to build websites in the late 90's similarly. Then progressed by reading blogs of other developers who shared their source in their posts.

It made sense back then because it was all we had to learn. Today there's tons of code to learn from both in open source and resources.

Lets get rid of this false dichotomy that the only way to learn is by viewing the source of websites, in the year 2024.


It's because of the mentality that things should be open and inspectable that we have things like browser devtools (thanks Firebug!), that is something we still use today to learn and troubleshoot. Sometimes it makes it harder when people use various compile-to-js/css languages, but also sometimes people ship their sourcemaps and again we can learn from examples. Or we try to reverse-engineer it, which is another valuable skill.

I didn't mean to say this is the only way of learning, but I stand firm on that it's still a great way to learn, to look at how cool stuff was done when you come across it on real websites, not just from blog posts describing something. In addition to reading fundamentals, practicing small projects and so on, of course.


It wasn’t an opinion, but I think you gave me the answer anyway, which seems to be “students learning CSS”. I never learned CSS like this, so I wouldn't think of it.

I started learning CSS only about 6 years ago. So I had Stack Overflow and MDN web docs for it.


The answer, as with all code, is "you, six months from now".

Anything that makes your code less readable is a fail. I understand that people want to treat CSS and HTML as assembly, but that's a leaky metaphor, and only works insofar as you never have to debug an actual webpage.

Every place I've ever seen with tailwind has struggled with front end work, because the end result is so horribly abstracted from the code.


That code posted above is the compiled code in the browser.

The developing code is not unreadable like that one. I think Tailwind is very readable during development. Even if I had only used in side projects.


Yes, I know. Tailwind emits this kind of gibberish as a compilation step, which makes it much harder to figure out what's breaking when you're using a browser inspector or something. Which of the 83 different classes is the problem? Good luck!

You have to have a certain level of discipline to write clean CSS, but it really isn't that hard. It shouldn't take a 300-character inline style to make a button, when you can use CSS as intended, and have a class named "button".


The meaning of 'compiled' has shifted quite a bit. We used to say transpiled when the output wasn't byte or machine code.


I think we've lost some of the coolness of the old web from this mentality. We turned website source code from a txt to a pdf.


It's how I learned web development


What does it look like when developing?


Much prefer reading this and making a change in place, than to go through a bunch of overloaded class names (e.g., 'container') in dozens of .css files just to adjust something like a margin on it.


I don't think this is a very good example, because it's not just "a box with rounded corners and a top and bottom section". It's a fully styled box containing formatted code (leading to a lot of spans and classes for individual chars in this code).


This isn't exactly honest but it's still funny.


When you format that code, it's easily readable.


as opposed to the very intuitive css one liner?


> Standalone CLI — we haven’t worked on a standalone CLI for the new engine yet, but will absolutely have it before the v4.0 release.

This part is the most exciting to me. Given the rest of the release announcement, I'm assuming this means that it'll be built in Rust rather than embed Node. While I'm not a Rust zealot of anything, I'm very partial to not embedding Node. Particularly when it depends on using Vercel's now-abandoned pkg[1] tool.

[1] https://github.com/vercel/pkg


It'll likely embed Node I'm afraid — the vast majority of Tailwind is written in JS so we'd have to rewrite all of that in Rust just for the standalone CLI, and migrating the entire project to Rust is impractical because we'd have no JS plugin story like we do now.


The current standalone tailwind CLI does not support external plugins like DaisyUI. It would be great if external plugins could be supported in the next CLI version, it will reduce the need to use npm for some projects.


This is handy for that specific need: https://github.com/dobicinaitis/tailwind-cli-extra

But I strongly agree.


Thanks, that looks like what I was looking for, did not find that when I looked few months back. I tried it now and had some issues with SIP check on macOS, started a discussion in the repo.


Don't you need to use npm to install DaisyUI though? If you have to install third party plugins using node already to me the solution is to use our actual node CLI instead of the standalone one.


The way I was thinking this would work is that the standalone CLI could be configured to pick up plugins from a specified location. That way as long as the plugins are setup locally in the required format, the standalone CLI would be able to load them. The setup process need not require npm.

There is a sibling comment which mentioned a project which is trying to bundle DaisyUI specifically with the standalone CLI. That would solve my use case but will not be a generic solution for other plugins.


Bummer, but thanks for resetting my expectations :)


I'm feeling a similar disappointment here, although I'm sure this was carefully considered by the Tailwind team.

I've been working with a fully Rust-based web stack, and it's been such a joy. Tailwind compilation causes me to still deal with Node. I'd love to see that go away.


Lots of promising improvements. I'm most excited about being able to control the theme via CSS instead of having to extend via JS.


Same excitement here, I had to drop into css to write this yesterday, as extend in the config file did not like it

    .vertical-center-line {
      background: linear-gradient(#000, #000) no-repeat center/2px 100%;
    }
    .horizontal-left-center-line {
      background: linear-gradient(to right, #000, #000) no-repeat left/50% 2px;
    }
    .horizontal-right-center-line {
      background: linear-gradient(to right, #000, #000) no-repeat right/50% 2px;
    }


My friends: do we need tailwind as soon as Safari 17.4 is out? Chrome has @scope already available and safari soon. With @scope we don’t need utility frameworks at all and can make use of scoped css with css variables for unification. What do you think?


Hasn't FireFox been dragging their asses on @scope? https://github.com/mozilla/standards-positions/issues/472

It took years to just convince them of the need for it. And I'm not sure anyone got convinced vs Chrome had already shipped it and Safari has it planned so they caved in. The most recent update I'm aware of is that it's "worth prototyping".

Hard to believe FireFox used to be a leader of the modern web.


I mean, there are the millions upon millions of devices that don’t run up to date safari versions. While @scope is awesome, the reality is that preprocessed nesting is super easy to use now and to rip out later. You’re only hurting users (likely poorer, less tech savvy ones) by jumping ship immediately.

In 2026, sure! Go nuts and rip it all out, but give people a bit to update first unless your target market is SF tech influencers.


I am not a front end developer, but I do maintain a few websites and I have used Tailwind for all of them.

My general take of the overall quality is that the maintainers of Tailwind have really good intuition in terms of what to prioritize, as well as excellent design taste. Tailwind is one of those tools where it only makes sense once you start to use it, but each version they've announced brings a continuously more polished product.

If you don't like Tailwind or you don't understand it or if anything I'm saying makes you mad, try first building something big with it. It's pretty maintainable, easy to read and write, and, most of all, is very portable. (I mean that in the sense that something you write in one place can be copy and pasted somewhere else and it will more than likely work exactly the same.)

As far as this version is concerned, it looks like not a whole lot has changed from a compatibility perspective, but I think when version 4 becomes official it might have more breaking changes. In any case, the prospect of a new engine is very cool, as faster builds are always welcome.

Congratulations to the team! I may not be a front end engineer, but with Tailwind I don't really have to be to make what I want.


> It's pretty maintainable

> something you write in one place can be copy and pasted somewhere else

That sounds like the opposite of maintainable.


The copy and paste statement related to portability, and that's how I was defining it in this context. It was not intended to speak to Tailwind's maintainability.

However, a traditional class-based, modular approach to CSS can not guarantee portability in the same way. So if you can not predict what effect the same classes, or even the exact same HTML, will have, then it's neither portable nor is it very maintainable either.


Out of curiosity, does anyone out there use tailwindcss with htmx (or other hateoas approach)? You obviously don’t want to have your hypertext representative of application state to have anything to do with styling, but something like tailwind can be odds with that. Cascading style sheets and hateoas obviously go together perfectly, as it’s markup and styling decoupled as god intended, but with something like tailwindcss, what are people doing?


I don’t have much insight into htmx + Tailwind, since the last time I worked with Tailwind was like 8 months ago at my prior job - and even then I did very little styling work. With that said, it’s not really clear to me what the connection is between HATEOAS and Tailwind.

FWIW, for the app I’m working on currently, I’m outsourcing most of my styles to Bootstrap, while pushing hard for progressive enhancement via CSS hacks (for effects like expanding/collapsing menus and switching tabs). I’m using htmx when JS is enabled, and regular HTTP for when it’s disabled (the Django back-end renders partial or full pages based on request type). Bootstrap and htmx don’t really step on each other’s toes, and I don’t see why htmx + Tailwind to be different.

If in doubt, experiment!


I use Tailwind at work daily and I still believe it is a crutch for a bad design system. I see pros and cons. If you keep your class count relatively small, you can "see" how the element is going to look if you are good with CSS, and it is incredibly intuitive. On the other hand, when you see blocks with 20+ classes, just like some examples posted here, they are hideous and all the readability goes down the drain, I take this should be made up for with the use of components and limiting copy pasting. Also I don't think you have to use either Tailwind or more classical approaches, in fact I like mixing both. During a rush a couple of years ago my team had to give a more up to date look to mane features in our app and, provided you have a strong component system, those touch ups were mostly related to positioning and sizing, and that represents 99% of our usage of Tailwind.


Looks like a lot of great improvements, but wanted to put in one vote in favor of keeping the capability of having a JavaScript-forward configuration/usage approach, rather than requiring a CSS-forward approach.

For us, one big benefit of using Tailwind has been that we can avoid spending a lot of time thinking about CSS and CSS tooling, and being able to configure everything via JS has helped in that regard.


That's exactly why critics of Tailwind (like myself) have been so frustrated…Tailwind shouldn't mean you avoid spending time "thinking about CSS". CSS should be a principal and respected pillar of a website's architecture, every bit as vitally important to reason about and understand as anything JS-related. Tailwind v4 promoting CSS-first configuration and customization, and allowing design token usage in vanilla CSS, knocks down a major complaint we've had regarding the framework.


I wish tailwind would support attributify like https://github.com/unocss/unocss, which is much more readable for complex layouts:

  <a bg="red" text="white" dark="bg:red text:white">link</a>


I was excited to use this in my Demo project, but `import from "node:@tailwindcss/postcss@latest"` throws error about the `exports` field in package.json.

With that aside, the blog post mentions not having to use `postcss-import` but it seems to include that as dependency. So we're still using `postcss-import`.


Is there any good tutorial/ guide available with best practices for tailwind?


There's a couple of good playlists by Adam himself on Youtube that are very useful in seeing how Tailwind should be used: https://www.youtube.com/@AdamWathan/playlists


Will have a look. Thank you.


The docs are great and they also happen to be a kind of "CSS: The Good Parts." What sort of questions do you need answered? For the most part you just make components and put styles on them.


Right now I have the feeling when using tailwind the html code becomes unreadable cluttered with classes. So abstraction of components is king? Maybe I'm just overthinking it.


Yeah, I would say using components (rather than classes with @apply, as another commenter said) is the main thing. The class clutter is then contained to that component. You make some components and then in most of your code there are only a few classes here and there.

Here's an example from my main work app:

Components: https://github.com/oxidecomputer/console/blob/da07ce01a8fb7f...

Clean call site: https://github.com/oxidecomputer/console/blob/da07ce01a8fb7f...


Either your html becomes verbose or your css becomes inscrutable. Pick your poison.


I thought styled components solved this issue pretty well. Your markup (JSX) is composable, and so is its styling (styled components with raw CSS or object syntax).

Unfortunately, many developers using styled components don't realize the power of their composability, and end up just writing one level deep for each component. But in fact you can wrap styled components and compose them together...


Styled components are no different than Tailwind in this regard, and this is precisely how Tailwind is meant to be used. You define a component and use that.


Do not use @apply. Embrace the chaos.


buildui.com has an excellent tutorial


If an org can't organise its workflow (name things) and adopt external organisation (magic bullet frameworks), the org will always have poor organisation in the long term.


I honestly can't tell whether this is meant to be for or against Tailwind. Is Tailwind a utility for organizing your workflow or a magic bullet framework?


Switching the theme configuration to CSS variables makes a ton of sense.

But what is the point of introducing a directive called "@theme{}" though for configuration?

Why not just do ":root{}"?


We considered it but it felt too magical to make any CSS variable under `:root` automatically drive the existence of utility classes. Putting things under a custom at-rule like `@theme` makes that opt-in, because we know anything you put there is actually intended to drive your utility classes.


Makes sense! Thanks for the reply, Adam.

Best of luck and thanks for driving progress forward with the project still.


Apparently they do that too

> We also make all of your theme values available as native CSS variables in your custom CSS

theme() makes using them more tailwind-y


How does people solve component variants? Say <Button type="success" size="lg"> or <Button type="danger" size="sm"> ?

For optimal gzipping (and saner readability) it's recommended to have sorted classes (prettier-plugin-tailwindcss)

But if you want to have some overridability (avoid clashing of p-4 and p-8) you need tailwind-merge.

These two don't play together well


  Button.css
I find it's often easier/cleaner to just pop a CSS file in for some of these foundational components that have tons of variations. Can use nested CSS now, and the selectors are easier to to work with IMHO and take care of specificity.


You could use the !important variants for overrides instead of merge. In v4, the tailwind team has already said they want to introduce a solution to solve this problem without tools like tw-merge. I’m guessing it will be some sort of modifier that is placed at a lower specificity if you know that you are authoring something that will be overridden later.


I think they most likely will introduce `@layout`s and then your components can be in a different layout than your app code


This is not a complaint. But as someone who uses AI heavily for tailwind, I found that GPT-4 couldn't update the syntax even after the cutoff is updated. Likely it gives equal weightage to documents regardless of the date. And even with 2023 cutoff it just can't work with new syntax of many libraries I tried.

I had hopes with google in this as they already likely have things like official docs, updation etc labelled so they can give different weights to every document. But then there is Gemini.


Have you experimented with Retrieval-Augmented Generation (RAG)?

Here's a good primer on it: https://aws.amazon.com/what-is/retrieval-augmented-generatio...

And here's a recent HN thread about RAG on PostgreSQL: https://news.ycombinator.com/item?id=39613669


Yes, it's not as good as the base knowledge of the model. And in a way even chatgpt/bing web search is RAG.


>Last summer at Tailwind Connect ...

Wow, a CSS library with a developer event and Apple style keynotes.


That’s where the big bucks are.


Everything about this sounds like how I expected Tailwind to work the first time I tried it.

I wanted to love it, but instead got bogged down in all this PostCSS nonsense and configuration before I could do anything.

Happy to see they're moving towards a "it just works out of the box" approach.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: