Hacker News new | ask | show | jobs
by llamaimperative 702 days ago
The point is that it’s ridiculously fast to build and extremely easy to maintain. It’s also not hard to read after, idk, a week of working in it? The only people I’ve seen struggle beyond that are people who dug in their heels and dogmatically decided to struggle with it.

FWIW for a Button, your engineer should just encapsulate all the “ridiculous” styling into a <Button /> element.

6 comments

I strongly disagree on the maintainability. Mistakes are easy to make and have been made when comparing a list of 20 class names across a dozen elements. Its only "maintainable" if you ignore the class list when reading. I review my local evangelists' tailwind code and from their mistakes its clear they're not reading the class list.

It reminds me of how some people claim they're great at multitasking and can text & drive with no issues - meanwhile not even being aware of what they're missing.

Tailwind has its uses, but it should not be the default choice.

I’ve experienced the exact same thing. Most TW evangelists I know are admittedly not that great at CSS. Those who are generally prefer a library like MUI instead, which offers the same maintainability benefits, a far more consistent UI, but with a higher learning curve.
> a far more consistent UI

That's what I like about tailwindcss - unlike MUI and co, it lets you follow sane design rules laid by tailwind and yet make the website look different from the rest.

Consistency of UI entirely depends on the user of tailwind.

As an end user (not developer) I'd take just about any design system over MUI. It's so clunky/heavy, has an abundance of useless white space, and just feels really outdated.
I'd love to love MUI, but in my experience: MUI + React + Typescript just moves the toil of doing anything away from the style concerns and makes it a purely Typescript puzzle.
Strongly disagree, Tailwind should be a first choice for anyone reaching for their first utility/css framework. Tailwind imposes a very minimally opinionated styling system, that can easily be broken out of when a developer needs to.

I wrote about some of my thoughts here about tailwind and the design system it imposes: https://alexmason.me/blog/2024-03-02-tailwind-made-css-great...

But if they use tailwind classes wrong, they would use css styles wrong too.
What kind of mistakes are easy to make? And why are you “comparing” class name lists?
All this talk reminded me of the extensions I installed to deal with these issues.
> FWIW for a Button, your engineer should just encapsulate all the “ridiculous” styling into a <Button /> element.

Sure thing.

What I don't understand though is why not put a Button.css file next to the Button element file, and describe all the button styles in there. What's so hard about building or maintaining that?

Soon after, you're going to need slightly adjust that button, you will add some helper classes. Then there will be a case when base style of that button doesn't work with new button style, and now you have 2 bases for a button. You might have semantically named those buttons, but 3 months later that no longer makes sense, and now you're afraid to rename it.

Tailwind lets you style elements in the same file as the element, you don't have to switch between `button.<whatever you use>` and `button.css` to know what is going on.

nah, I love tailwindcss.

> Soon after, you're going to need slightly adjust that button

The proper thing to do, in my mind, is to gradually set up a collection of such buttons (and other components), and document their properties. A design system, if you will. You shouldn't have that many button variations.

This should also help with the "3 months later" case. Once you've catalogued your buttons, you can reason about them, update their styles, rename them as you please, and so on, while maintaining consistency of buttons across your site.

1 - It’s easy for style bugs to get introduced when someone updates the html and forgets the css.

2 - It’s simpler to have styles that depend on js vars/parameters when components handle their own styling.

Encapsulation, in other words.

You lost me at ‘maintain’. It’s definitely not easier than just updating a single .button class, and I’m not going to create reusable components out of everything in my project, the <Button /> approach doesn’t work for everything.
Yes, it is easier to maintain

(assuming no css-in-js) Your styles are bound to the component, not some global in your app.

States and their representations are controlled in the component themselves

With normal css files and class names, you must jump between files. With tailwind, I see what's going on with a component right in my jawascript

You’re assuming I’m going to create a component out of any element on the page that needs styling. In my project I could just have a small handful of these scattered across hundreds of files:

<table class=“datatable”>

If I used tailwind utility classes, how do I update my data table styling without having to search and replace across all of my files? Assuming you could even search and replace, the utility classes could be in a different order. Not saying it’s not doable, but it seems like a real pain in the ass. What am I missing?

The things it doesn't work for are the things that .button doesn't work for either.
After writing Tailwind for a few years, I've kinda shifted position on the maintainability of it.

It's definitely easier than any alternative, but it's also painful to read through a giant list of classes. There's no getting around that.

I think a better way to put it is that Tailwind optimizes for writes vs reads. It sacrifices the readability of HTML for the writability of CSS.

I still think that's a worthwhile tradeoff, but it's definitely a tradeoff.

> FWIW for a Button, your engineer should just encapsulate all the “ridiculous” styling into a <Button /> element.

And pray you never have to tweak or debug that element.

Hiding away bad code where you don't have to look at it doesn't stop it from being bad.

Open the browser tools, select the element, view the styles and look what class cause the problem. Nothing else would you do, if you had a problem in styles css file.
If you can’t follow a DOM tree through some custom components to debug uhhhh… maybe practice more.
The point was, obviously, that the styling string doesn't go away if you hide it inside an element.
Then I’m failing to see why it’s “bad” other than the verbosity/visual noise, which does in fact go away if you hide it (this is the point of abstraction in general, of course)
It's adequate for some folks who work in the same codebase, and define their own style of work. It's been a real pain for me who comes in to various codebases for short periods of time and have to read/digest/learn every single project's unique take on buttons.

class="btn btn-primary" is also pretty easy to read. But in the last couple weeks I've have to deal with both class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-md shadow-md" style buttons and <LinkButton4 /> and <LinkButton7 /> components, both of which still seemed to be affected by another wrapping container that decided to "text-xs" everything below it, but which wasn't obvious. Trying to simply add a 'button' that had the same styles around it was far more work than it should have been.

No doubt, I'm somehow in a minority of switching between projects/codebases more often than other people. But this was much less of a problem with bootstrap and related definitions.

> your engineer should just encapsulate all the “ridiculous” styling into a <Button /> element.

When you want, say, most things to share some common color/style definitions, you will still end up repeating a lot of stuff (same long string for buttons, and for headers, etc). The tailwind system gives you the option of @apply, but the tw docs are also relatively strongly against it, for ... I can't really understand the reason why.

https://tailwindcss.com/docs/reusing-styles

> If you’re going to use @apply, use it for very small, highly reusable things like buttons and form controls — and even then only if you’re not using a framework like React where a component would be a better choice.

There's some reasons listed on that page justifying "don't use @apply!" but... they don't ring all that useful to me. They do say "well, you could do it for reusable things like buttons", but those are the very things that most tailwind examples use longhand examples for.

> Yes, HTML templates littered with Tailwind classes are kind of ugly. Making changes in a project that has tons of custom CSS is worse.

There's a balance between the 'ugly' (their words) and 'tons of custom css'. Everyone's balance is different, I get it, but I'm usually having to come in after someone who was jazzed about tailwind has moved on and left me the 'ugly' (their words) mess. If every link should have "text-dark font-bold font-xs"... @apply that with an understandable name. Or document your design decisions...? But that conflicts with "ridiculously fast to build". Documenting them in an '@apply' way would let me see how you want some styles grouped together without having to scan through dozens of your components looking for a pattern.

> without having to scan through dozens of your components looking for a pattern

Wouldn't you have to scan disparately located CSS files anyway? How many projects have you seen with nonsensical or clobbered classnames or conflicting rules?

Really for a lot of designs I think you can just eyeball it. If `px-4` looks about right, then use it. Otherwise you can find a similar component and hijack the exact padding if you want, or get it from the design.

You probably think @apply makes more sense because you know and like traditional CSS. You want to apply tailwind classes and condense them into a single reusable one. Tailwind asks you to think in a different way. The classes are aptly named (mostly) and granular (one class per css directive), so my knowledge of CSS felt very transferable.

  <LinkButton4 />
Imo should be

  <LinkButton variant={"homepage"} />
Leveraging something like Class Variance Authority or more simply:

  <LinkButton className="text-xl other-override-here" />
Using tailwind-merge

I have found tailwind to be indispensable, and it pairs particularly well with React.

Again, at least part of the core issues I have is coming in to other projects where each person thinks in a 'different way'. And almost all of them are simply copy/pasting loads of tailwind extended strings of stuff, then semi randomly tweaking until something looks 'ok', then moving on.

> scan disparately located CSS files anyway

usually, I encounter CSS in one of two ways:

1. a main base css file or set of files (from a framework, maybe), and then an override css file. Single override file can get hairy to look through, admittedly, but it's typically in one spot. I rarely come across projects with dozens of standalone css files.

2. 'style-in-components' - primarily in vue, because vue sfc encourages scoped styling - structure, code, style in a single file. Whether that's bootstrap styling ('btn btn-primary', etc) or tailwind doesn't make too much of a difference.

Where I've hit more maintenance issues is coming in to projects with tailwind in say, react or vue - with the 'style in components' - is that "text-xs px-1 rounded-sm bg-gray-200 inline-block text-gray-600 mb-1" repeated across multiple components, is harder to find when I want to replicate something vs just "class='tooltip'"

Of course, we're all doing it wrong, and if we all just 'think different' all the time, and spend loads of time rewriting "wrong" stuff from other people - things will be just fine. But the world I live in, and the world I see a lot of people in - is not greenfield, but brownfield, and we have to live with the decisions others made. Tailwind does not make my life any easier that way, and generally introduces more cognitive overhead earlier in a project when it comes to visual stuff.