Brian Lovin
/
Hacker News
Daily Digest email

Get the top HN stories in your inbox every day.

satvikpendem

I've used Tailwind extensively at previous companies and inevitably each one creates an abstraction that's akin to:

    const headerClasses = [(list of Tailwind classes here)];

    <header className={...headerClasses}>...</header>
because the complexity of reading and writing all of the classes is just too much. At that point, you've just reinvented CSS classes. Tailwind fans will tell you to not do this but if multiple companies are independently having the same problem and coming up with the same solution, the onus is not on the user anymore, it's on the creator to fix it. @apply can work but again it's really not recommended by Tailwind itself, for whatever reason.

These days I recommend learning CSS really well and then using Vanilla Extract (https://vanilla-extract.style), a CSS in TypeScript library that compiles down to raw CSS, basically using TS as your preprocessor instead of SCSS. For dynamic styles, they have an optional small runtime.

They have a Stitches-like API called Recipes that's phenomenal as well, especially for design systems, you can define your variants and what CSS needs to be applied for each one, so you can map your design components 1-to-1 with your code:

import { recipe } from '@vanilla-extract/recipes';

export const button = recipe({ base: { borderRadius: 6 },

  variants: {
    color: {
      neutral: { background: 'whitesmoke' },
      brand: { background: 'blueviolet' },
      accent: { background: 'slateblue' }
    },
    size: {
      small: { padding: 12 },
      medium: { padding: 16 },
      large: { padding: 24 }
    },
    rounded: {
      true: { borderRadius: 999 }
    }
  },

  // Applied when multiple variants are set at once
  compoundVariants: [
    {
      variants: {
        color: 'neutral',
        size: 'large'
      },
      style: {
        background: 'ghostwhite'
      }
    }
  ],

  defaultVariants: {
    color: 'accent',
    size: 'medium'
  }
});

Impressive that OP still is using ReasonReact, I thought it was all but dead after ReScript.

pcthrowaway

I actually agree with this criticism, and it's the best criticism of Tailwind I've seen so far.

I still love using it, and will continue to do so. This isn't enough to stop me from using it. Normally I try to avoid this, and abstract the repeated bundle of tailwind classes in a component instead (it can be a container component or just some useful utility component to avoid having to repeat the same group of classes too much). This can have its own drawbacks, because having too many custom components that you need to remember to use in given situations (which is effectively how most design-systems would work anyway) makes the codebase less approachable.

And even still, we'll end up using the above trick (referencing a group of classes bundled into a property of an object somewhere else) from time to time, as well as the obvious option of just repeating classes as necessary. Referencing classes from an imported object is annoying too, because it breaks intellisense.

I'm honestly not sure what a better solution is though, because Tailwind has really sped things up for me compared to CSS/Sass/Chakra/Material.

nwienert

Tamagui really aims to solve this problem and some of the usability problems of className by putting style props directly on the props. You can nest components and abstract them as you want and still get the Tailwind style shorthands except as TS typed tokens.

No worry about how you reference things or static-ness etc and the final output can be flattened down to just div + css even across module boundaries or when nesting multiple times.

pcthrowaway

Interesting.. so is Tamagui using react under the hood, but "hiding" it from you to some extent? Does it provide some helpers for responsiveness?

simonhamp

I believe the solution here is most definitely @apply. I know the Tailwind team seem to be against @apply (and even flirted with removing it), but having used it extensively to build complex (imo) sites and apps, @apply has been unavoidable and actually great to have.

The fact is @apply is there and if we're using it and there's enough push-back, I don't see why the Tailwind team wouldn't listen to that or create a workable upgrade path for those who wish to continue to use it.

So use the tools you have - don't avoid it just because the core team dislike it. They can't remove it in the version you have installed today (unless they have some magical way to reach into your computer/server)

di4na

The real answer is in CSS developing a proper supported way to do mixins.

I keep being surprised that noone bring this up in these discussions.

presentation

I do it with emotion (CSS in JS), specifically NOT using styled components and instead using the CSS prop which allows for composing styles more naturally, and it works great. Never felt a need to get my team on Tailwind since it’s already super productive with the right set of mixins.

blowski

In general, framework owners _want_ you to become tightly coupled to the framework, whereas as a user you want to be able to move away from it more easily. I think this conflict of interests is behind recommendations like this, rather than sound technical reasons.

abujazar

Why would framework owners want you to become tightly coupled to the framework? They're basically just offering a set of solutions that come with some tradeoffs, but they don't intentionally create problems for their users.

tekkk

Yeah I don't understand what the other solution would be. If you want to have reusable styles, eg "btn" class with all your defaults @apply is the obvious choice. Otherwise you'll end up with similar gargantuan CSS class spagetti and/or have to abstract away some generic components because handling the classes is just too much.

mvf4z7

I was under the impression that you create a button component and apply the atomic styles in that component. That way you don’t don’t need a “btn” class, you just use the Button component anywhere you need a button.

satvikpendem

Sure, I've already moved onto CSS in TS solutions like vanilla-extract above though, I like my typechecking in my CSS.

balfirevic

  > const headerClasses = [(list of Tailwind classes here)];
  > <header className={...headerClasses}>...</header>
Why wouldn't they extract the header as a higher-order component? That would make more sense even without Tailwind, and I haven't heard anyone in the Tailwind community advocate against that.

have_faith

I think this is just an example but `header` is a standard HTML element. It's not always necassary to seperate every single element into it's own component. Every time you make a framework component you add overhead to the rendering of the app.

balfirevic

> It's not always necassary to seperate every single element into it's own component.

It's not necessary but in the given case it's obviously useful as there is more to abstract than just the html element - the styling.

replygirl

> Every time you make a framework component you add overhead to the rendering of the app.

not true, separating components by concern can save you a lot of fiddling with memoization

akvadrako

Attributify mostly solves readability issue:

  <button
    bg="blue-400 hover:blue-500 dark:blue-500 dark:hover:blue-600"
    text="sm white"
    font="mono light"
    p="y-2 x-4"
    border="2 rounded blue-200"
  >
https://windicss.org/features/attributify.html

redbar0n

It solves the repetition and collation into className, yes.

But I think the author's main gripe was that component abstraction was made difficult with Tailwind when you want to customize the component from the outside, by dynamically altering the styles through props (as often needed for contextualization in design systems), and not just no-prop components like Tailwind suggests: https://tailwindcss.com/#component-driven

naasking

> At that point, you've just reinvented CSS classes.

Sort of, except instead of context switching between CSS, HTML, JS and your programming language, you can now remove the CSS entirely. Less context switching is good.

I'm a Tailwind fan and I don't see a problem with that pattern for some cases. Obviously there are better ways to organize that should be preferred in general, but it's fine to do that here and there.

arrow7000

You still have to context switch between thinking about markup vs styling vs behaviour. The language you write the styling in barely makes a difference imo

naasking

Sure, but you don't have to switch between types of files, syntax, etc. "Barely makes a difference" seem subjective, so YMMV.

lazy_moderator1

all kinds of companies make bad choices, i've also seen a bunch of companies use tailwind correctly -> components + @apply are enough to make it very pleasant to work with :)

satvikpendem

While that may be true, as I mentioned, if many companies repeatedly keep making the same errors (including a sibling commenter here), it is on the creator to fix it, not the user, and even if they do, it could be a bad solution. Personally I've moved off of Tailwind entirely, too many footguns to deal with, and I'm not sure why it's any better than writing CSS, at scale, not prototyping. In a way, it feels like the CSS version of Perl or APL these days.

TeMPOraL

> In a way, it feels like the CSS version of Perl or APL these days.

Perl, maybe, but not APL. CSS version of APL would let me style my personal site and blog in less characters than it took me to write this comment :).

replygirl

windicss is a superset of tailwind that lets you define shortcuts and aliases for easier composition, and variant grouping for less typing

b93rn

[flagged]

satvikpendem

No, I haven't. As I said I've worked in several companies that explicitly have this sort of abstraction. If so, what's the point of using Tailwind? Tailwind fans will say it's atomic classes, but when using them with many devs, it indeed turns into reinventing CSS classes.

So, perhaps it's the other way around, that Tailwind is simply not a good tool at scale.

piaste

As I understand it, Tailwind is essentially CSS 2.0 - or 5.0 I guess - with the warts ironed out (sorry for the unpleasant mixed metaphor):

A) CSS / Tailwind: lots of little 'atomic' classes describing individual visual properties. Easy to understand, easy to customize, but slow to read, slow to get started, with plenty of stuff to learn

B) CSS frameworks / Tailwind-based components: fewer classes declaratively describing the component's role (eg 'btn-primary'). Quick to get started, elegant to read, but prone to abstraction leakage and trickier to bend to your own exact specifications

There's always been a need for both kind of tools for different projects and there will always be, in the same way that e.g. network programming may involve anything from bit-banging commands to high-level protocols.

(And you will often go back and forth in the same project: you quickly crap out your first draft using prebuilt components, then it turns into a serious project and you start actually investing time in design and twiddle with the individual properties, and eventually it grows to a large project where you now have to go back to components again for the sake of maintainability, but this time it's your own components with your own accumulated set of properties.)

Over the years CSS frameworks kept improving, but CSS was much slower to do so - although it acquired flexbox, grid, etc., the language limitations stayed, and they were bad enough to e.g. spawn SASS/LESS out of a genuine need for better maintainability.

Tailwind takes all the stuff that was added to CSS over two decades, like media queries, and makes it part of the core nu-CSS language design. Tailwind saw a ton of hype and adoption because all the developers who had always wanted to go the (A) road now had a well-designed set of simple classes they could use with a lot less hassle, plus a bunch of developers who had adopted (B) because it was the road that had all the momentum suddenly realized that they probably wanted to use (A) once it was made less painful.

Many of the flame wars between "pro-Tailwind" and "anti-Tailwind" people were actually disagreement over whether to take the A or the B road.

Using @apply, header classes, or component projects like DaisyUI somewhat resembles using a CSS framework like Bootstrap, but by building on top of Tailwind it means that, when your project or resources grow and you want to move from (B) to fully customizing your style in (A), you will be able to write your individual little graphic touches in Tailwind instead of plain CSS.

vehemenz

I don’t understand. Do you think there is something in the CSS spec that dictates developers must use high-abstraction classes? What do you think CSS classes are?

apineda

That is likely the gist of it. I love tailwind for prototyping / designing in code, for large code bases, not so much.

antihero

Tailwind shines when paired with a component based library such as react. If you’re repeating the classes all the time, perhaps create a component for that.

dubcanada

This should be called "Don't use Tailwind in a React library for a design system" as this really has nothing to do with Tailwind and is all about integration of Tailwind into a React design system.

None of these "negatives" are "negatives" for using it as part of a standard HTML/CSS website outside of React. The comparison between readability of a bunch of divs and web components or react makes no sense, of course <SidebarItem /> is easier to read then <div class="flex-1 bg-blue font-bold, text-md d:none"></div> but nobody writes React like that. Everyone will have a SidebarItem component that spits out that div.

franky47

I do write like that. Heck, even a mix of both: <SidebarItem marginRight={2} />, using Chakra-UI [1] (not too dissimilar to Tailwind in spirit).

Even the best design system needs local overrides to satisfy a product owner's incomprehensible requests, like "can we push that button a few pixels to the left?".

[1] https://chakra-ui.com/

_nhh

The whole point of a design system is not to have local overrides.

In a design system. You specify variants of a component. Each one has its own combination of style defined by the design system.

You do not set „Gap“ to 2. you would specify smth like „small“, „medium“ or „large“ as props.

This is not a tailwind issue.

franky47

`2` in this case is a design token that is defined in a theme, that would resolve to a length defined in a CSS unit (ideally rem).

How would you handle a design change where a size becomes required that fits between "small" and "medium"? These things happen throughout the lifetime of a project.

Opaque numerical design tokens may not be the most explicit to understand, but they allow for expansion.

wry_discontent

> The whole point of a design system is not to have local overrides.

Are you unfamiliar with having-a-boss?

adamscybot

Right, huge +1 for Chakra. Chakra is basically tailwind but built on react primitives. It feels lot cleaner, and solves most of the issues mentioned.

franky47

It's amazing for quick UI building.

Note however that this API is brought by Styled System [1], which Chakra uses (and exposes), and adds the component library and other niceties on top.

My only regret with Chakra is that it's a tad runtime-heavy, and it's not really adapted to static content. I'd love to see some sort of compiler that digests a React tree into rendered HTML + CSS, with minimal JS just for style interactions (is this what Svelte does?)

[1] https://styled-system.com/

zmxz

This was the reply I was looking for. Thank you.

I don't know the purpose of misleading title, I guess this is how web works now - capture attention by misleading readers, then criticize the actual layer that causes problems, but hide the fact that the one in chair is at fault for not being a capable user of technology.

Jenk

I'm guilty of implementing

    <SideBarItem />
as

    export { SideBarItem = (<div class="flex-1 bg-blue font-bold, text-md d:none"></div>) }
Is that a bad thing? (Genuinely asking for opinions)

E: added clarity

nerdywordy

No, it's not a bad thing.

It's how (nearly) everyone using React (or any frontend framework) + Tailwind will structure their code. And I'm not sure the author is arguing against Tailwind's utility in static styling scenarios.

I think the article's author would argue that once you move beyond static classes that Tailwind's class building becomes messy.

So <SideBarItem padding={4} active={true} /> would be cleaner in the authors mind if the exposed props get applied by some other tooling better suited for dynamic styling instead of simple string manipulation.

There is some merit to that argument. Building the class string can be cumbersome in some scenarios. But Tailwind "clicks" for me where other solutions do not. So I do it anyways.

zdragnar

It lends itself to copy-pasting everywhere. Styles end up getting over-applied. Markup becomes 3x harder to scan because the signal: noise ratio is horribly skewed.

YMMV; I prefer styled/ emotion-styled for primary, reusable blocks, and tailwind for one-off exceptions like a bit of extra margin.

digitalsankhara

If I were to look at your code (or revisiting my own after some time) I'd know what <SideBarItem /> was likely for straight away. But I would need to construct the likely intent of the <div> version in my mind. Of course you could abstract those classes into one that provides semantics;

<div class="side-bar-item"></div>

Jenk

I meant SideBarItem's implementation is the tailwind div, but is referenced as SideBarItem like any other React component, not that the tailwind div is pasted all over. :)

undefined

[deleted]

sally_glance

IMO it's not a bad thing at all unless you have that exact div snippet copy-pasted to a thousand other files.

Jenk

I meant SideBarItem's implementation is the tailwind div, but is referenced as SideBarItem like any other React component, not that the tailwind div is pasted all over. :)

nextaccountic

It's not a bad thing.

Or if it's a bad thing, I'm guilty too

franciscop

> "but nobody writes React like that"

If it's "possible" people WILL write code like that. That's why I like styled-components, you are FORCED to separate the style definition and then you can say nobody writes code like that. But dozens of style classes mixed with functionality? People DO write code like that, a lot more than I like admitting seeing myself.

michaelteter

This is why I have a hard time getting on the Tailwind bandwagon. It feels like a pipeline equivalent to "margin: 1px 0 0 4px;" and other element-specific stylings _everywhere_.

CSS brought some opportunity for structure. At least it started out as "define a common style for a thing", and then if you really wanted to make a small deviation you could inherit and override something from the class.

Could be that since I'm not a frontender I just don't get it, but to me it feels like "global variables everywhere".

robswc

As a full stack that is mostly backend, I like the way CSS frameworks allow me to not have to worry too much about design. I originally used CSS "properly" but I found that it was a chore/pain basically recreating these CSS frameworks over and over.

It can get messy pretty fast but I find once you sorta get a handle on the frameworks, it becomes easy to parse as long as people aren't doing 10+ classes per element.

I've found working without a CSS framework, people will tend to re-invent the wheel 100 times. i.e. I've seen "padded-box" and "box-with-padding" classes.

I experience the worst of the worst tho, as I do a lot of refactoring work, so my take is a bit bias haha.

redbar0n

> This should be called "Don't use Tailwind in a React library for a design system"

That's true.

> as this really has nothing to do with Tailwind

Well.. it has to do with using Tailwind with React for a design system. :)

He does mention that @apply doesn't fix the problems he mentions, which is what Tailwind suggests as the solution for abstraction when you don't use a component framework: https://tailwindcss.com/#component-driven (scroll down to "Not into component frameworks?")

firemelt

that is javascript programmer they think everyone write javascript

manxman

Is it just me or has the underlying purpose and value of “cascading” in CSS been lost within these abstractions.

The only real limitations with CSS imho was just lack of variable support for easily passing in variables to set color schemes and/or dimensions etc.

These seemed to be readily fixed with SCSS and the various options for embedding CSS in JS using styled components and the like.

Tailwind seems to be all about making it easy to “pixel f*k” your way to getting the design you want in one given place at the expense of having consistency and maintainability.

E.g. with a proper CSS template I can ensure all fonts and sizes and colors are consistent across an app. With Tailwind everything starts to be like the 1990s where all your design was hard coded into table and font elements mixed into your markup!

This does NOT seem like progress!

kaba0

The underlying purpose for the “cascading” was customizing the look of documents by the user. We seldom have truly static web documents any more and this use case is non-existent even for those.

In my experience cascading is simply not a great idea even in itself — you can’t reasonably share part of your design between different components, it causes way too close coupling, breaking some non-intended component on some other page. What can reasonably be shared is variables and a color palette, which you can specify at a single place with tailwind.

But my point, design seems to primarily think in components - so just create a component in your framework/webcomponent, design it locally (e.g. by tailwind) and reuse that widget where you want.

manxman

I don’t think it’s about “documents” versus “components”. It’s about consistency and maintainability.

Keep the local styling for the component local to its place in your repository - absolutely. Give it sensible defaults - for sure. But if you’re using it in something complex where the overall design may evolve it’s a maintainability nightmare to hardcode the styling at the component level and/or designing by classname.

I get why initial development is faster BUT… if you want to make a simple style change on a 100 component site - do you really want to be editing a load of components for every change down the line?

zmxz

Out of curiosity, have you used Tailwind and does your criticism come from having used it and not experiencing the progress or does your criticism come from reading how it works and not "feeling" it? I don't intend to follow up with discussion that convinces/dissuades/criticizes you in any way, I just ask purely out of curiosity.

nobleach

I'm not the one you're asking but, I messed around with it a bit and it really left a bad taste in my mouth. There is just much hype behind it though, so I bought the book to really get a feel for it. I liked the book. I used it in a project and after going back to code written by a few members of the team, it just felt like an unmaintainable mess. The common response whenever I share this sentiment is one of:

* You don't know what you're doing * You're doing it wrong * You're an idiot.

It really kinda feels like the old AngularJS 1.x days as those were the typical responses to anyone who didn't fall down and worship it as a framework masterpiece. I've decided for myself, I'll sit this one out. Judging by history, most of the things we were fanatical about at first, we tend to look at with disdain in a few short years. jQuery, AngularJS, Bootstrap, Redux... It would be foolish to think this library/framework won't go the same way.

If you use it, and it works for you and your team, that's great. I would never try to tell you NOT to. For me, I'd rather not.

strogonoff

I had the chance to use Tailwind recently. I don’t think it’s disputable that in a sense it mocks the “cascading” part of CSS, though I’m not sure I’d hold that against Tailwind. It often felt as taking a shortcut to me, but it could be a worthy tradeoff and so far I have not noticed Tailwind overly complicating maintenance and development of an average project. That said, I don’t think I would choose Tailwind if I could use, e.g., web components with scoped styles or something similarly more in line with the spirit so to speak.

manxman

Yea I’ve used and I think it’s cool for prototyping quickly but the idea of coming back and making edits to it in production code a year from now terrifies the bejeezus out of me.

kaba0

If you apply it to a component that you reuse then how is it unmaintainable?

vehemenz

Tailwind is much, much faster than building your own stylesheets with deeper abstractions.

In most cases, it is faster to use Tailwind than customizing an existing UI framework.

SCSS and CSS in JS are more complex solutions than Tailwind.

Maintainability is generally better with Tailwind because you don’t need to remember all of your abstractions and any hidden structures, eg this div.className always needs to be nested a certain way. Onboarding is trivial because Tailwind can be mastered in two afternoons.

Tailwind might not be for everyone, but the features it provides allow for rapid development and easy maintenance. The author has issues with Tailwind in React, but these seem mire like React complexity than Tailwind.

gonzofish

I’ve liked the CUBE methodology since I first saw it. It takes all the ideas of these utility classes, but combines it with a BEM-lite approach to work with the cascade, not against it.

https://cube.fyi

caseyf

Yes! Use Tailwind for the "U"

marcosdumay

Well, yeah, the entire point of Tailwind is to not use CSS like it was supposed to be used.

Some people like this better. It reminds me of people that used to adjust the format of every single text area on Word instead of using styles. And on some contexts, that's even objectively better.

But most of the time it's just a bunch of developers arguing against generalization and encapsulation. I don't understand it either.

Anyway, just to add a bit:

> The only real limitations with CSS imho was just lack of variable support for easily passing in variables to set color schemes and/or dimensions etc.

Nowadays CSS has variables support that you can use for that.

dmitriid

> Is it just me or has the underlying purpose and value of “cascading” in CSS been lost within these abstractions.

For app-like websites CSS cascade offers little and is often harmful as an innocent change to a top layer will unpredictably cascade down to everything below.

> at the expense of having consistency and maintainability.

Compared to what. Every single website devolves into a nightmare of incomprehensible class names, or one-off CSS-in-JS solutions everywhere.

Compared to that the actually consistent names enforced by Tailwind are both consistent and maintainable.

caseyf

I find that using utilities where appropriate is a win, not everything need be extracted into a stylesheet or component.

Having a standard library of utilities makes sense because if you don't use one you end up writing the exact same thin since they are mostly one liners.

What I don't understand is why you'd want to build a design system component out of utilities much less build everything out of utilities.

redbar0n

Here's an example that might give an idea: https://tailwindcss.com/#component-driven

undefined

[deleted]

lyxsus

tbh, tailwind feels like the worst thing that happened to frontend dev since coffee script.

redbar0n

Have you seen "The modern way to write TypeScript"? https://github.com/DanielXMoore/Civet

*runs for cover*

lyxsus

omg. ok, adopting some F features is an interesting idea. but why are they trying to make that thing with syntax happen?

madeofpalk

Arguably coffeescript was a big push to move JS spec forward into ES6 and beyond.

dimitrisnl

I've been using Tailwind for my component library and I don't agree. For example "It is optimised for writing, but not for reading" is certainly a problem, but this is why I created a component library. To abstract this.

Also this is weird:

``` const Card = (props) => { const className = "p-" + props.gap.toString(); return <div className={className} />; }; ```

Why do this? If gap needs to be set, then break apart the Card subcomponents (Card.Title, Card.Description, Card.Footer) and let the consumer handle their odd logic that break the design system guidelines.

I have faced issues with Tailwind too, but I would pick this 10 out of 10 times over styled-components and such.

hnbad

FWIW this code would also break with newer versions of Tailwind as it tries to generate a Tailwind class name on the fly. Tailwind needs all class names to be statically analyzable (via very dumb pattern matching) to pare down the infinite list of possible class names to something you can actually write to a CSS file for production.

On a related note, the article's example of why Tailwind is clumsier for a Box component misses out on the addition of the `space-y-{number}` and `space-x-{number}` class names, which are equivalent to the "gap" props in its React example. But I think those didn't exist in March 2021 so I don't blame the author.

iamsaitam

You can provide a whitelist of classes you use dynamically in the config file.

stefanfisk

Concatenating Tailwind classes is a huge code smell. While you can safe list them, I've personally never done anything where I felt that it was worth the effort compared to just listing all possible classes.

danielvaughn

I like to use a library called classnames. It lets you define dynamically-applied classes in a much more readable way.

https://www.npmjs.com/package/classnames

dugmartin

Another (smaller) alternative is clsx: https://www.npmjs.com/package/clsx

vehemenz

A good middle ground is to have your linter sort the classnames in a reasonable way. I prefer the “outside in” method. This keeps things readable enough so you can find classes where you expect them.

danielvaughn

I would like some kind of editor plugin that would collapse all classNames by default. That would help a lot with Tailwind readability.

HuwFulcher

I don't use React or do much front-end work so I might be missing something here but what's the problem? Tailwind is a utility-first framework. If you're having to add so many classes inline that it makes things more difficult you can surely abstract it away within CSS files?

I thought the main thrust of Tailwind is that you get a sensible set of utility classes so you can mix and match them how you need? For more complicated design systems can't you combine these utility classes into your own classes in a CSS file? You still retain the advantage of easier to read CSS and easier to read JSX.

jkrubin

I am with you. I personally never have understood css to begin with. I like styled-components (et al (emotion and other css in js things)) because it makes distributing components with styles saner, but I really don’t do much front-end.

I am always blown away with what raw css can do and would like to learn it, but it doesn’t click for me. When I first heard about tailwind I thought it was awesome sounding as I don’t jive with css, but when I tried it I was dismayed to have YET ANOTHER build step and thing I had to screw with and configure outside of the src code.

ls15

> @apply is the directive that Tailwind recommend to extract repeated utility patterns. Since it's a static definition, you would only abstract those lists into a CSS file. I don't want to get into much details about it, but it does not solve the problems mentioned before.

I would like to know why @apply does not solve the issues in the author's opinion. This is exactly the part where the author should have gone into details.

nonethewiser

Probably the same as this reasoning:

> Even that this snapshot of code-UI is doable in Tailwind, at some level of those components you will find a layer with a bunch of classNames that you need to parse in your head in order to imagine the UI.

So he would probably say that @apply just abstracts away the problem but it still exists somewhere that you'd need to parse through to understand the styling.

But this doesn't resonate with me. This isn't avoidable in any scenario. Either you have a styled component with a bunch of css-in-js, or a bunch of css, or a bunch of utility classes. In all scenarios there is an implementation that you have to parse. Which basically means it has nothing to do with @apply and everything to do with css vs. utility classes.

undefined

[deleted]

rmckayfleming

Pretty much every thread on Tailwind will devolve into debates on CSS development/maintenance practices. My take is that Tailwind enables a style of CSS development more akin to using a dynamically typed language. It's really great for whipping things up and for one offs. And for so many tasks, that's all you need!

But of course, there are situations where it becomes unwieldy. I'd wager that a lot of the problems people have with Tailwind are more social in nature. Which are valid problems! It just means that you need some other solution for that. Analogously, many of the benefits of static typing are social in nature; notably in enforcing interfaces between teams. I suspect people are looking for a similar thing for CSS. But that doesn't invalidate the use cases where Tailwind is particularly handy.

EduardoBautista

> Tailwind isn't component-driven, which they claim to be

They don't ever claim to be component-driven. They are utility-class library and nothing else.

I highly recommend using twin.macro if you are using React. It basically combines tailwind with styled components and helps immensely with readability:

https://github.com/ben-rogerson/twin.macro

danielvaughn

The author makes a couple of valid points, although these aren’t reasons to not use Tailwind. Rather, they’re just the trade-offs you have to sacrifice for the benefits that Tailwind provides. Whether the trade-offs are worth it depend on your use case and your professional opinion.

That being said, when looking at Tailwinds problems, you have to ask yourself “compared to what?” Especially that first complaint - Tailwind is hard to change compared to…Bootstrap? Foundation? BEM? MUI? It’s vastly, vastly easier to change Tailwind code than any of those frameworks (IMO).

I’m a Tailwind champion not because it’s the perfect solution, but because I’ve found it to be better overall than anything that came before it.

jamager

Agreed. For me an increasingly important factor is documentation. Good documentation can save so MUCH time and headaches, and tailwind's is so good that I have an easier time accepting its defects and trade-offs on that basis alone.

danielvaughn

The tooling around Tailwind is so good. The VSCode intellisense plugin auto-suggests tailwind classes for me, which means I don’t even need to reference the docs unless I’m looking for obscure functionality. It’s amazing.

cutler

I've found VS Code's Tailwind intellisense to be unreliable. Half the time it just doesn't generate anything.

jamager

Yes!, Jetbrains works very well to.

redbar0n

> “compared to what?” Especially that first complaint - Tailwind is hard to change compared to…

The author compared it to Chakra UI (in the last code sample; misspelled Charkra).

He recommends ThemeUI, Rebass, Stitches and Radix for a design systems, specifically. A recent and very powerful alternative is Tamagui which takes inspiration from all of those.

nwienert

Tamagui actually does solve all four of the mentioned problems in the article.

One nice thing is that it does so in a way that allows for avoiding doubling the depth of your component tree by having to do HOC type solutions as many seem to do to work around them.

dmitriid

> Tamagui actually does solve all four of the mentioned problems in the article.

How?

The very first example in Tamagui docs is this:

  export const Circle = styled(Stack, {
    backgroundColor: '$background',
    color: '$color9',
    borderRadius: 100_000_000,

    variants: {
      pin: {
        top: {
          position: 'absolute',
          top: 0,
        },
      },

      size: {
        '...size': (size, { tokens }) => {
          return {
            width: tokens.size[size] ?? size,
            height: tokens.size[size] ?? size,
          }
        },
      },
    } as const,
  })
It's already worse than Tailwind. And the rest is just a bunch of predefined components that you can do with any library/framework/vanilla CSS.

undefined

[deleted]

meet_zaveri

Started my web dev in bootstrap era. When I found out about tailwind and tried it in one of my side project, I never looked back.

In one of my prev companies, I was able convince my engineering manager to use tailwind alongside Antd and it worked flawlessly.

Just to make a point here, Antd is an example of design system and I used tailwind as a "utility" from which I can use vast amount of classes without writing seperate custom css for each of my components.

rhodysurf

We do the same and haven’t had any problems mixing antd and tailwind

sonicgear1

Please don't follow the author's opinion. RadixUI with its' 50kB tooltip is not something a sane person would use. This is why React websites weight multiple megabytes at times.

redbar0n

The author recommends ThemeUI, Rebass, Stitches and Radix for design systems, specifically. They might add undue bundle size, to various degrees. Looks like Radix' tooltip is now at 12.77 kB: https://www.radix-ui.com/docs/primitives/components/tooltip

But a recent and very powerful alternative is Tamagui which takes inspiration from all of those. All for the cost of some 20-27kB, apparently with a clear path to come below 8 kB in the future: https://tamagui.dev/blog/version-one#bundle-size-reduction

It even has a tooltip feature, using floating-ui, which one may or may not add, and seems to come in at around 23 kB (in excess of tamagui core, when overlapping sub-libraries in @floating-ui/react-dom-interactions are discounted)... https://bundlephobia.com/package/@tamagui/tooltip@1.0.5 It's still a bit, but fortunately it's not in core so it's optional to include.

johnrackles

This code example is explicitly not supported in tailwind:

  const className = "p-" + props.gap.toString();
according to https://tailwindcss.com/docs/content-configuration#dynamic-c...
Daily Digest email

Get the top HN stories in your inbox every day.

Don't use Tailwind for a design system (2021) - Hacker News