> The biggest drawback to CSS Modules is the lack of design system utilities.
There is nothing preventing anybody from using design systems with CSS Modules.
The author makes it sound like you need stuff like Tailwind in order to leverage design systems. This is completely misleading.
> I have used Tailwind UI as a starting point and inspiration for my own components.
There are loads of UI libraries you can use as a starting point & inspiration with CSS modules as well.
The concept of a design system is orthogonal from one's styling solution of choice (CSS modules, Tailwind, CSS-in-JS).
The author certainly knows how to write a blog post and does a good job at selling Tailwind. But in my opinion he doesn't have enough experience to give this kind of opinionated advice to others yet.
Exactly. This post is extremely unconvincing. The vast majority of the post is explaining the background of what CSS Modules is, what CSS-in-JS is, what Tailwind is... Then then "Implementation Strategy" section is three whole paragraphs, with no real details about the implementation. I honestly wonder how people would set up a design system with Tailwind. I don't see how to do it without it being a mess. I've done it with CSS Modules and CSS vars and it's lovely.
I'll just throw out there that I'm someone who's been developing for a long time but never been able to get into web dev.
It just always feels clunky for me, there's way too many divergent approaches, best practices are constantly moving.
-
I'm designing a web frontend for an embedded project I'm working on and decided on Mithril + Typescript + Tailwind CSS and DaisyUI.
And it's the first time I've felt productive with web tooling.
Tailwind/Daisy UI makes so much more sense than any other styling approach I've ever tried.
I mean, is there a reason I wouldn't want to say an element is a "large red button" rather than a "setup-wizard-login-button" and defining that somewhere else?
Maybe I'm missing something that becomes a problem at a larger scale but for me this utility based approach is great.
Interesting. I've had a theory that Tailwind appeals to full-stack developers more than dedicated web front end developers. If you have to jump from context to context a lot, adding one new context (separate CSS), is an actual burden. All the extra abstraction can seem like a waste of time.
> I mean, is there a reason I wouldn't want to say an element is a "large red button" rather than a "setup-wizard-login-button" and defining that somewhere else
I wouldn't create a `setup-wizard-login-button` class. That's getting too granular. In the apps I've worked on there's usually been a `<Button>` component that encapsulates a lot more functionality than just being large and red. It deals with stuff like accessibility, custom disabled states, transitions, etc. It makes sense to encapsulate all of that into one component, then use something like `<Button type='primary'/>` everywhere. In this example, `primary` would map to a design token for a particular style that would handle all the permutations of how that style affects other states, transitions, etc. If you're just applying `large red button`, you're not getting any of that stuff, and I don't see a good reuse pattern for it. So I suppose it depends on how complicated your design system requirements are.
Author here, would you be interested to read a deep dive of how I'm using Tailwind? I wanted to include it here, but the addition made the post unbearably long.
Also, if you have written about your design system implementation with CSS Modules and CSS variables, I'd love to read it.
Hi! I'm someone who worked with a designer closely to create a style guide/system and a React component library (using styled-components) for our product.
I don't see how Tailwind would've made our job any easier, or the implementation any "better" than what it is now. So, I'd definitely love to hear a non-vague (most Tailwind CSS praise I find around is very broad strokes or vague) success story.
Like, concrete examples where Tailwind reduced complexity or helped DX-wise, (etc) would be really appreciated. I believe there's many others like me who think Tailwind is kinda cool and we wouldn't mind playing with it in personal projects, but would hesitate to choose it at work/production...
I love the productivity idea its trying to sell me, but it sounds a bit... Wrong to me? Maybe I'm just too "old school", even if I'd like to think I'm keeping up lol.
Author here, it depends on what your designer has made. Our designer was using the Tailwind Figma file for the redesign with most of the defaults in place. We added our brand green and a different font to the default config.
When I was working through some of the component structures and spacing, the designer explained to me which Tailwind values he used most often and in what scenarios. For example, spacing around sections/containers was 24px or p-6; spacing within sections (like between form inputs) was 12px or p-3; and spacing within elements (like between button icon and text) was 6px or p-1.5.
While these were not absolutes in the redesign, they greatly sped up my scaffolding and allowed my first passes to be either dead-on or close enough to reason about. And when it was close enough (but not dead-on), toggling up or down a value usually settled it to match the mocks.
Personally, this was the easiest time I've had for getting an implementation "pixel perfect." I chalk this up as a design system win more than Tailwind. Any well-defined design system would open up these collaboration benefits. I found Tailwind to be an asset to these both for my own DX and for collaboration with my designer. I think Theme UI or styled-components could fit that goal just as well.
Ah, I see. I was working on the web portion of a system that was meant to encompass web, mobile, and smart TV devices, and was very custom. The designers would not have even considered using off-the-shelf Tailwind values, and the mobile teams would not have wanted to translate a web-framework's values into mobile-land. I suppose if you have an organization that's ok with that constraint, that makes it more doable.
> I chalk this up as a design system win more than Tailwind. Any well-defined design system would open up these collaboration benefits. I found Tailwind to be an asset to these both for my own DX and for collaboration with my designer.
Yeah, this seems like the real takeaway. If you have a framework that gives you defaults for the design system, that reduces the friction even more, but I tend to work on very custom stuff where framework defaults won't be appropriate. Are the Tailwind values customizable, so you can use the same Tailwind structure, but have your designers specify their own tokens?
Absolutely. The Tailwind config makes this really powerful to extend or override. You can reuse the same API for things like spacing with your own values/scale or make your own.
Here is the spacing section in my config where I've extended the default with interstitial values. What's really cool is these propagate to all the spacing utilities (padding, margin, margin between, etc)
> > I chalk this up as a design system win more than Tailwind. Any well-defined design system would open up these collaboration benefits. I found Tailwind to be an asset to these both for my own DX and for collaboration with my designer.
>
> Yeah, this seems like the real takeaway
And to add:
> Our designer was using the Tailwind Figma file for the redesign with most of the defaults in place.
I never really thought of Tailwind as something that provides design primitives designers could also use for their designs.
If everyone on the team knows how to use Tailwind, I can see how it helps productivity. Everyone's using the same primitives and they're speaking the same design "dialect" (for a lack of better word).
Your example with negative/white space units is a really great, because it illustrates how it dispells ambiguity around units and numbers, and it brings an vocabulary for talking about those units. For example, I really like that `p-3` means the same thing to both the designer and the developer now.
Before a designer would have some systems for managing various design sub-systems (ie typography, colour, spacing), that developers rarely (ie never) spend time understanding, which then removed the system's internal consistency, which in turn affects its perceived/external consistency.
Tailwind kinda leaks the design-system's implementation details, which is great for developers, because now they don't have to know anything about design systems, just use what the designer provided.
Absolutely, I would love to see a longer write up! I’m definitely in the CSS Modules camp, but with so many people saying that Tailwind is great, I feel like there has to be something there. I want to do a deep dive into it at some point and see if I can make something with it that works with my brain. It’s such a different way of approaching the problem.
As for my experience with CSS Modules, I don’t have a blog, but I’ve been thinking of starting one and writing up some of my experiences. Can’t promise anything though.
Tailwind seems to force users to learn its API on top of having to learn CSS, without removing the need to learn the app-specific conventions you’d have to use/create when using Components or classNames anyway.
What benefit does it provide? All I could glean from your post was that you used it and got the job done.
That's pretty much how i felt about this post. A design system is independent of it's implementation, the swatchlike presetting Tailwind provides (and is often confusingly referred to as the "design system") is achievable with css variables or preprocessors just the same.
don't get me wrong utility classes have a place in CSS - but they should be introduced as needed.
Writing all your styles with utility classes makes it easy to just sprinkle in changes and flavours directly in your components, but come at the cost of having a mess of class strings everywhere that make it very hard to further maintain the project when it gets more complex.
css-in-js bring about the same pitfalls, all your styles are sprinkled in your templates and get modified and overwritten in places where components are called instead of providing a top down view of how things should look. Responsiveness makes it an even bigger mess and hard to control global aspects of the design.
I strongly believe that decoupled, BEM-type styling systems with a solid variable based configuration, and a well thought out and DRY cascade together with utility classes for specific recurring needs are still superior to just dumping the styles inside each and every component as you go along.
I get why people are skeptical of Tailwind, and I was too when I started a job at a new place that used it for their frontend, but now I'm totally onboard and use it for all my personal projects. Incidentally I'm wearing my TailwindCSS shirt today!
It really fixed a whole slew of my biggest pain-points with CSS. The biggest one being that you have to jump between files when modifying a single UI. Which isn't just annoying while developing, but it's also even more frustrating when refactoring and you have to come back to some files you haven't touched in a long time, trying to cross-reference ID names and styles between the template and the CSS.
It's also just way more concise than typing CSS which helps with the fast iteration. e.g. jumping to a different file and typing
#id-name {
margin: auto;
}
vs just being in the tag and typing
`class="m-auto"`
Maybe it doesn't seem like that huge of a difference, but I find it saves me so much mental overhead when I'm in the flow of putting together a UI, and I work way faster now. It's also really not that difficult to learn the syntax, which stays pretty consistent throughout all the different CSS properties you can apply. Also the responsive syntax is so much nicer than the typical "@media screen blah blah" syntax is vanilla CSS
On top of this, it's not even just a different way of writing CSS - you inherently end up working in a built-in design system that you can tweak to your liking. For example, the margins go up in units of 0.25rem, it comes with a pretty good built-in color palette (that you can add to/modify in the config), etc. Which keeps you on something of a consistent grid, and is really good for teams where you don't want some new guy coming in using weird sizings or units.
If you don't like the idea, I'd urge you to give it a real shot, even on a small application. Try converting styles on a page to Tailwind. I think it's worth it in the long run.
On conciseness (and possibly scale), isn’t the css “bloat” just being shifted to the html file instead? Has there been sufficient studies in comparing tailwind to say something like:
.MyHeading {color: red; font-weight: bold}
// Left container
<h1 class=“MyHeading”…
// Right container
<h1 class=“MyHeading”…
What's the point of a .MyHeading class in this instance? Why are you spending so much time naming things solely to reference them in a separate file?
In my Tailwind projects I can have an entire components/ directory with just .jsx files. No more having to spend time naming one-off elements, or cross-referencing class names with separate definitions in separate files.
> No more having to spend time naming one-off elements
Doesn't this make them untargetable if you ever use it somewhere else? Plus, it already has a CSS name: whatever you named the component (and therefore its folder).
UI code should be modular, component-based, and lends itself to being logically grouped into single folders or files:
MyComponent
->index.tsx
->style.css
Or for vue just MyComponent, etc.
Now, this component has all the abilities that we tap into these frameworks for in the first place: it's composable, it's targetable by a known & unique name, we can use it anywhere without restriction.
I don't even want to imagine a world where I render some component and it has no targetable name... Terrible for reuse
What do you mean by targetable? The only thing that should be modifying the styles of MyComponent is itself. Any necessary changes should be exposed through the component's public API. Because of this, whether the styles live inside the component itself or in an adjacent css file doesn't matter.
What he means by naming one off elements is that within MyComponent there are multiple native elements that may need to be styled.
Maybe I don't understand your concept of reuse well, but I certainly don't think all components can just be slapped into the flow of an arbitrary parent container and have the right positioning and styling for free, and if you have to target those off of emergent behavior (i.e. Tailwind classes making it look some way), you are doing something very error-prone.
I also don't think it makes sense to imply the component's creator can know all possible circumstances it will be rendered in and can therefore make an insightful API to control these things. Instead, we can target the fact that CSS is a public API to control styling choices, and expose the classic handle into that API...
I disagree that you commonly need to style component internals from the outside. But when you do, exposing html class name injection points works fine. By no means should you be writing css to target a component's internals from outside of the component's own css file. That leads to a mess and is the opposite of reusable. The HTML structure of a component is private.
> I disagree that you commonly need to style component internals from the outside
Can you say more? For example, if any use case for it exists - which you seem to agree - surely you can see anyone inside such a use case would prefer to have this for free.
For example, I built a nice declarative form using React. I reuse my own Input fields and such. To control their spacing, I target their classNames for some occasions, like "MyLibraryInput" etc.. To be clear, this className belongs to the top level parent of that HTML structure and no styles of the type I described interact with the private HTML of that component, which I am surprised I have to state given that you are responding to a comment stating "I certainly don't think all components can just be slapped into the flow of an arbitrary parent container and have the right positioning and styling for free" and "we can target the fact that CSS is a public API" for single elements because that's quite exactly what it is...
> exposing html class name injection points works fine
So, after all this about how this use case is invalid, you just argue that someone who needs to do this type of thing should have to make extra wiring for no reason? I mean, certainly it functions, but it's a completely unnecessary step to force consumers to go thru. I do not understand this perspective at all.
The class names inside MyLibraryInput are, even at its top level, private implementation details. To control spacing of them in a form, you should add additional class names to their root, via a public API that allows adding class names, or by styling their parent as a flex box or similar, or by having a spacing control in its API. You should not be targeting them through CSS at all.
It's not extra wiring for no reason, it's extra wiring to ensure maintainability. When you style children via css like `#parent .child` you are making it difficult to understand where and why styles are being applied. Any parent at any level of nesting could overwrite the styles of any child, potentially conflicting with other ancestor overwrites. And as the internals of the component change, all these overwrites may stop working correctly. By making the class name injection points explicit, even if it's just the root, you are avoiding this problem of "where did all these styles on my input come from??" and "what is going to break if I change this class name?"
A point that is not immediately front of mind in these discussions is that Gzip/brotli makes these comparisons moot. Similar strings will be referenced with a pointer and take basically zero extra bits down the wire. That's one place where tailwind get's a huge boost. It's a ton of repetitive code that compresses extremely well.
If you use a plugin to sort your class names like Headwind[0] then it can be optimized even further.
> The biggest one being that you have to jump between files when modifying a single UI.
This is why I still like Vue files over React ones. Vue files can have a <template> tag containing the HTML structure of the component, a <script> tag containing the functionality, and a <style> tag containing the CSS.
That's one of the things I like about Svelte and Vue, everything is together in one file. Here's a simple example from the Svelte tutorial: https://svelte.dev/tutorial/numeric-inputs (click the "Show me" button).
I've used both. I prefer Vue for the continuity between other projects using CSS. Styled components is fine but it adds just a little more friction and ambiguity.
With Vue I know exactly where the CSS goes. With Styled components, Im still in JS land where things can be defined wherever whilly-nilly as a template string; imported, passed around, and manipulated. It's a small thing, but those add up.
Yeah, I don't get styled components, the syntax and organization looks like a mess. I love using Stylus with Vue single-file-components, it lets me use a lot of CSS-specific patterns and macros.
Using Stylus blocks, I like making things responsive just by defining a media query in a block and then doing like:
> It really fixed a whole slew of my biggest pain-points with CSS. The biggest one being that you have to jump between files when modifying a single UI.
I’ve heard this before, and I’m always confused by it. The way I build components is that the component has one co-located scss file that lives right next to the jsx. MyComponent.jsx has a MyComponent.scss. It may import other mixins, functions, or variables using @use, but I usually don’t have to actually navigate to any of those files. So, I’m usually just looking at that one component scss file. How are people structuring their css that they’re dealing with multiple files for a single component? Will one part of the component have a class from one file and another have a class from another file?
OP means you are looking at both the structure of the DOM (JSX) and the CSS (className).
The “tailwind” effect is due to fast feedback and iteration - there is no jumping between two files (DOM file and CSS file).
Of course this also leads components eventually having huge lists of classes.
But I think the fast feedback loop is worth it, because with 2D visual artefacts and the complex CSS language, often the only way to learn/get what you want is change a little, reflect, change a little, … etc.
> there is no jumping between two files (DOM file and CSS file)
I don't view this as any more difficult than navigating a long file. Maybe I actually view it as more simple upon making that statement. What development environment are you using? Hotkeys to switch tabs is fairly base-level stuff
> often the only way to learn/get what you want is change a little, reflect, change a little
Which surely any person who is arguing for "fast feedback" would do using the browser's dev tools so you can edit CSS and instantly view the result in the same window as your actively painted view...
I would look into getting a proper editor like VSCode, setting up hotkeys, and learning to use dev tools if I was you. It sounds like you are using VIM to make your website
It’s not just the “jumping between files” that takes longer.
It is also mentally computing the “CSS cascade” to determine the final rules for a given DOM element, and keeping in mind all classes that apply.
The dev tools often cannot save styles back to your source code when you use a build step.
Even if I get my file switch down to 16ms, it is 16ms more than 0.
If I can view the JSX and see all the final styles on the element or on a nearby parent, it results in a faster feedback loop.
I am not for or against Tailwind, as I have mentioned this directness causes a lot of classes on single elements which can be hard to read later, but is often faster to edit whilst you are writing it.
> It’s not just the “jumping between files” that takes longer
This language you've used is imprecise and suggests jumping between files is a problem. The alternative is jumping from your IDE to Tailwind docs unless you are a tailwind expert no? This sounds like I'd measure it in seconds and not make a facile 16ms estimate so I could write 16ms > 0 and look smart...
> The dev tools often cannot save styles back to your source code when you use a build step.
... 5 seconds ago you were arguing about speed of iteration, now the fastest possible iterator is a problem because you have to manually curate what you save in the end. How is this not a problem when you're just slapping classnames onto something and hoping it looks right? You have to go back thru your save history or to git when you fuck up, again something I'd measure in seconds
> If I can view the JSX and see all the final styles on the element or on a nearby parent, it results in a faster feedback loop
> It is also mentally computing the “CSS cascade” to determine the final rules for a given DOM element, and keeping in mind all classes that apply.
I just feel like you must be really bad at CSS to feel this way. CSS should interact with a component's private structure only in that component's CSS file, it should expose styling & sizing variables thru a CSS var API, and its top-level container's style & position are the only legally targetable things by someone else rendering it. This does not leave any room for having to "keep in mind all classes that apply", that is a drawback only to Tailwind.
Anyways, I don't get why you argue in this fashion just to walk it back at the end as "faster to edit whilst writing" when you discarded the fastest possible solution because of externalities to it that you're unwilling to consider here. For example, loading up a normal component, I simply glance at its CSS file to see all styles applied to it; not so many fancy layers. This means it is very fast to resume writing it. For Tailwind, you clearly need to first build the mental model of all the styles applied and any interactions between them, and then second you need to go to Tailwind docs to see what styles are actually being applied in terms of CSS. It has a layer of misdirection that drastically reduces speed if you don't just sweep it under the carpet. "Dev tools can't autosave for you" is an absurd complaint in the face of brushing all this aside
I can work with or without Tailwind to be honest, I was commenting on the principles that are making Tailwind popular.
> The alternative is jumping from your IDE to Tailwind docs unless you are a tailwind expert no
No, as the class names directly map to CSS key/values and the IDE auto-completes the classes. If you know vanilla CSS, you would pick up the Tailwind classes quite quickly.
> "CSS should interact with a component's private structure only"
> "that is a drawback only to Tailwind"
CSS specificity/cascading is part of vanilla CSS.
And what happens to deeply nested components? Are you are using your build step to prevent CSS cascading, giving each of your component classes a UUID?
Instead of using the Chrome dev tools, I am currently using live reload to refresh the page after any HTML/CSS changes.
When you edit your HTML + CSS in the dev tools for fast feedback, are these edits written back to your CSS source files (I assume this is not possible, as they are part of the build process)?
> > The alternative is jumping from your IDE to Tailwind docs unless you are a tailwind expert no
> No, as the class names directly map to CSS key/values and the IDE auto-completes the classes
If true, definitely helpful, but I wouldn't necessarily say I agree with the assertion that it is a direct map. Looking at examples, I see craziness like `w-64` (width?) and `flex-none` (why?), and while I admit it is relatively terse it is quite clearly not just CSS.
> CSS specificity/cascading is part of vanilla CSS.
Yes, of course, but sharing CSS classes between disparate elements is the only time the developer has to consider CSS cascading, and so if you simply outlaw the practice you avoid the mental burden & all associated footguns entirely.
My CSS setup is React components styled with SASS. Each component HAS to expose a `className` hook which blends the consumer-provided className with the component.
i.e. <MyComponent className="SomeOtherClass" /> ==> <div class="MyComponent SomeOtherClass" />
The styles are private to each component, using only a few shared classes such as flex-* which behave as tailwind classes, but don't really specify anything fancy. Reuse of CSS if necessary is done thru mixins, but I generally don't find much need for CSS reuse.
When I want to change my CSS, I just directly use the browser's dev tools, and then port it back myself. If my component exposes some structure, let's say like a ConfirmationModal, then the the classes are extremely easy to spot:
<MyConfirmationModal className="AnotherClass" title={x} onConfirm={someFn} onCancel={someFn} /> ==>
No shared styles exist. Very easy to reason about. Editing something in dev tools edits something like MyConfirmationModal-userMessage which is going to be very easy to find in code. I usually write it in the browser and "stage" the text into in my CSS file but without saving if I need to modify multiple not-closely-grouped styles, but this isn't really a common flow so I just slap it into dev tools til it looks right then copy-paste into the corresponding block in my SASS structure
I guess I've never seen the problem with switching files. I have two tabs open and use cmd-shift-] and cmd-shift-[ to flip back and forth quickly. There's no friction at all. The benefits of keeping the concerns separate outweighs any benefits to only having one file open.
No, I agree, I develop with one .scss file per component. The issue is bouncing between markup and styles.
If I've got some outer div that's a container for other, inner things, why do I need a name for it? It's much easier to just say how it should look within the context of that component than it is to come up with a name and put the styles for that name in another area of code. I want a 1rem horizontal margin? I set a class of mx-4. No need to name it, no need to jump to another area of code, I just put the styles in the context of where I'm laying out the element.
> The biggest one being that you have to jump between files when modifying a single UI
Can you expand on why you were doing that in the first place?
Your comment reads like CSS just finally clicked for you (e.g. reusing classes instead of specific IDs, and the entire principle of cascading/inheritance) and are attributing that to Tailwind or something.
It’s a completely different approach from the normal way CSS is used. With Tailwind the classes describe what it should look like directly rather than what it is. Yes, it is still accomplished using CSS, but it’s definitely not the way most people use it.
Bootstrap and numerous other popular CSS frameworks, notably any with grid layout and/or utility classes, have done that for the past decade+. So Tailwind is the modern/popular CSS framework?
No, they haven't. Tailwind is basically just a lot of utility classes which you use to set css values.
Other frameworks generally combine multiple properties with their classes.
It is a very different design choice with it's own up and downsides but equating it to bootstrap is just silly.
It's more realistic to compare it to directly setting style attributes on html tags then bootstrap, but that wouldn't let you use responsive modifiers/dark mode nor be as concise.
Bootstrap has 98% of utility classes that you need for most projects. And if you use a design system or one of their themes, than the only 2% of css you have to modify is the color pallet and a few extra classes to cover edge cases.
Reinventing the wheel by subdividing all of your css into individual classes and combining them in html again just doesn't seem like a step forward to me.
> Bootstrap has 98% of utility classes that you need for most projects.
Including responsive classes? i.e. make this div X rem on mobile, Y rem on tablets, and Z rem on desktop? With 3 class attributes that require no config?
I don't get it. CSS Modules are designed to be combined with global utility classes. Using mainly utility classes is some OOCSS shenanigans we stopped doing literally decades ago. And CSS-in-JS has worse performance because styles aren't compiled to sytlesheets like they're supposed to be, they're applied at runtime. Downloading JS > parsing JS > executing JS > generating stylesheets > injecting stylesheets in to the DOM dynamically > repaint + reflows is how you get poor performance.
CSS is a solved problem and that solution is CSS modules with global utility classes compiled to static stylesheets.
I liked linaria at first, but it has been a huge headache and my team is eager to get away from it now.
A lot of helpful strategies like lazy loading components and inlining critical CSS are incompatible with linaria and cause very strange breakage due to changing precedence as components are loaded.
It's an awesome library when it works with what you need, but it's been a compatibility nightmare for us. So many popular tools in the JS ecosystem are a headache to get working with it.
I explored this a long time ago, but after a while, I was like "what's the point" and just went back to CSS Modules. I'll just write more classes and have a separate file in my directory if it means not adding even more shit that can break in my project.
Zero runtime css-in-js feels like the natural progression. It combines the best of both worlds and is very flexible, bring your own design system instead of relying on your css implementation to decide on one for you ala tailwind.
Also a Tachyons fan. I looked at TailwindCSS, but stopped at the installation section. The recommended path to get it working with Create-React-App is to install a bunch of JS packages (PostCSS, autoprefixer) and to layer on another tool over CRA (craco)? No thanks, I'd rather just <link> tachyons.min.css and move on.
As much as I hate JS packages, when I read why Tailwind is built the way it is…it made a lot more sense.
You basically generate the kitchen sink in dev and then rip out everything you’re not using when it’s deployed so the actual package size is really tiny.
Author here, while it's not the default, newer versions of Tailwind have an experimental Just In Time mode, which inverts the approach to generate styles as you type them rather than upfront. Using JIT has greatly sped up my development workflow. Changing the config is significantly faster than in normal mode.
Compared to Tachyons being tiny by default and you just add anything else you need in another CSS file. It's just another CSS file, why is the 'Tailwind way' so averse to using custom CSS? Instead it includes every style by default and uses a javascript build step to strip out the unnecessary styles, good grief.
Utility CSS classes should augment your CSS, not be your entire CSS.
This is changing with v3 that is slated to be released before the end of the year. The JIT compiler for Tailwind is becoming the default now that it has had a year+ to bake in the wild and prove itself as reliable.
As far as the toolchain goes, meh. Building on PostCSS allowed the Tailwind team a lot of power with minimal complexity and it appears to have paid off for them. The JIT is plenty fast as is now; so fast in fact, that you can now run it in on a CDN build for prototyping/MVP.
It's a shame that the Tailwind docs recommend to use craco. I think that's a major turn off. In that situation, I rolled my own npm-run-all customizations of the default scripts for start and build. It's extra noise but less than the documented approach.
Author here, I am eagerly awaiting the next version of Create React App. I'm hoping the upgraded internals will remove the need for CRACO. Here's a link to CRA v5 on Github:
It's because Tailwind looks good. It has well designed defaults & the documentation makes it look beautiful. I've used Tachyons before & enjoyed it, but it looks ugly in comparison.
If you're picking a framework that will eventually be used by developers who might not have any design skills, which would you prefer?
Part of it is marketing and part of it is the novelty of using inline utility classes, but none of this explosive growth happens without a deep focus on design at every stage.
Documentation, defaults, examples, and color palettes all matter.
This is somewhat apples to oranges, but look at Bootstraps' navbar example page versus Tailwind's (paid) examples. One is a cluttered mess, the other is a carefully designed list.
TailwindUI is not great comparison. Its a commercial product - bunch of snippets. You could build pretty similar thing with tachyons by replacing the class names to tachyons version.
I like tachyons looks more than tailwind but you can change tailwind using config to look exactly like tachyons but you cant turn tachyons into looking like tailwind.
based on just opening the first two links - if I was picking a framework that will eventually have to handle accessibility issues like wcag contrast rules I think I might say take that tachyons stuff.
although probably making a decision like that based on how the documentation for the framework looks isn't actually reasonable.
> making a decision like that based on how the documentation for the framework looks isn't actually reasonable
How much effort someone puts into their documentation tells me a lot about how much effort they put into the product in general, and user-friendliness in particular.
Are you implying Tailwind is operating as the traditional startup? It's the exact opposite. Fully profitable right now with 8+ employees and what I would assume is tons of the money in the bank having listened to tons of interviews by Adam Wathan.
The Tailwind team is just insanely talented and committed to quality at every level. Not everything is a SV game of marketing and smoke screens.
> Are you implying Tailwind is operating as the traditional startup?
No. I’m simply saying that the quality of a website does not indicate quality of the product being shown. The only thing that will indicate if a product is good or not is testing it.
Tailwind obviously has great marketing and a great developer base, but not everything is the same.
It might be partially marketing but there is one crutial difference between the two.
I like default tachyons style a lot better than tailwind but tacyons cannot be customized (atleast it couldnt when ive tried it). Tailwind is essentialy postcss functional css system generator. I suspect most companies are going for specific colors/typography/spacing that fits their designs but follows tailwind naming. So that puts tachyons out of it.
I couldnt use tachyons in type of work i do but i can tailwind.
For me it looks like all terrible concepts in one place.
Please learn CSS, you'll see how fluid and easy it can be, and how many problems Tailwind introduces.
I recommend going with Pollen if you really need some kind of framework for CSS. I believe that's the way to really help with CSS development without the burden of learning yet another layer of abstraction over simple CSS.
I've been writing CSS since 2000 (when it was introduced). I'm not a ninja, but I know how to write it, and I love Tailwind.
Tailwind is not for "people who don't know CSS", it's a design system. A value prop of it is for teams who don't have a dedicated designer. Tailwind gives you a set of fixed "design decisions" in the form of utility classes, which is far more flexible than something like Bootstrap, while still offering set constraints (which brings uniformity).
Tailwind is not a replacement for CSS; it is a replacement for tedious, unnecessary toil that comes with naming, cross-referencing, and coupling HTML elements to CSS classes. In a world of web components, Angular, React, Vue, etc. there is no longer a need to separate styles from their components; refactoring your application such that components encapsulate their own style is a good thing.
I believe you still have to do some "cross-referencing, and coupling HTML elements to CSS classes" when using tailwind. The naming and creation of those classes is what the framework provides.
Except you're not actually talking about CSS. You're talking about CSS + a high-abstraction methodology.
Everyone who uses CSS uses a methodology, and that methodology comes with its own abstractions. For example, Tailwind is low abstraction; all you need to learn is how the config works and naming, which is relatively intuitive and can be learned in a day or two. After that you're dealing with mostly straight CSS properties.
Most methodologies people actually use when they implement "vanilla CSS" or SASS impose a high level of abstraction—naming, which classes do what, which classes map to which elements, how the DOM hierarchy must be structured, etc. Just because these things aren't necessarily committed to code anywhere (yikes) doesn't mean there's not a complex abstraction layer.
You seem to be convinced that Tailwind can be used without CSS knowledge. I just hope I'll never have to manage a project that took such statement serious.
Writing good CSS is hard, and is it’s own skill that needs to be learned and developed. Abstracting that out so the non css experts can create consistent interfaces without having to ‘learn css’ is the goal.
The biggest issue with inline styles is you can't use media queries or pseudo-classes like hover, focus, etc, which effectively means you can't build anything of substance with them.
Agree that if inline styles offered all of the features you get when writing your CSS in a stylesheet that it would be a compelling option because of the simplicity, even though the verbosity would be a big knock against.
I know you're the creator of Tailwind. However, using emotion’s css() from @emotion/react feels like the best of both worlds. Essentially, writing inline styles but with the ability to do media queries, pseudo classes, and conditional styling based on state. I didn’t like CSS modules, I never quite “got” Tailwind’s functional take on CSS which left me feeling inflexible, but I found something great with emotion and it works wonderfully.
In reality the difference wasn’t so big but inline styles might not scale well. (I also realize the original poster might have been sarcastic but it’s a fun to look into even the non serious ideas).
Tailwind also offers curated (and curatable) styles instead of a free-for-all. You can set up Tailwind to exactly provide the levels of spacing, colors, fonts, etc. that you want for your design system. Tailwind is in some ways like inline CSS, but enhanced inline CSS that you can customize the options of precisely for your project/team/company. You don't have to use text-xs, text-sm, text-lg. You can use text-fineprint, text-prose, text-inyourface and configure them to be exactly the size you want. And then of course, you can change the definition of those styles in one place and have it propagate throughout your project. This is where Tailwind starts to move well beyond inline CSS.
md:p-2 which is for m devices , make padding as 2
Or xl:p-4 , which is for xl devices , make padding as 4
Similarly for hover or focus in tailwind its
bg-white hover:bg-black focus:bg-red
Which says , by default keep background of this element white , when you hover over it keep it black and when you focus on it , keep it red
Works just fine,
Give it a try and go through the docs of tailwind, navigating it using algolia, is a joy :D
Can we all finally agree then that this is not an issue with modern frontend technology which allows you to componentize your stuff?
Yeah, it was bad when you had a hundred HTML files with repeated elements across them. Updating the style on one such element meant going through all these 100 files.
Nowadays, if you want to change your button background color or your container width size, you should be able to change a single component and have that updated for your whole website.
For me, that kinda fix the main issue people had when they started saying "do css, not inline styles".
I think a big problem with CSS is the assumed best practice of starting with the abstraction / module (stylesheet) instead of starting inline and refactoring out like you’d do when coding in any other language.
It creates paralysis and feels like an upfront chore/ cost. Then naturally it’s hard to maintain because you didn’t know what the right abstraction was yet. You literally end up with everything modular (css files) even if it’s only used once.
I’m really enjoying elm-ui and the principles behind it.
This is exactly what I tell people when explaining why I like tailwind. It's very freeing. I mean, I tell them other good things too, but this one is big.
Except you'd be missing out on Tailwind's constraints, which prevent someone like me (with not as much of an eye for design) from accidentally sneaking in little inconsistencies that make a design seem off.
(Like in another comment here, I'm rehashing a more extensive blog post [1] of mine here.)
Why do people prefer Tailwind to Bootstrap (css only)? THey both seem really similar but I've been using Bootstrap so long that I haven't had the impetus to change.
Bootstrap and Tailwind are very different, though newer versions of Bootstrap do have more utility classes like Tailwind.
Bootstrap provides pre-made visual components, which are useful for getting stuff built quickly but can be a huge pain to tweak (e.g. you want 99% of the styles but just need the padding to be slightly different in one instance).
Tailwind provides no pre-made visual components, but instead provides a sensible design system to keep things consistent, and either a much more pleasant and scalable way to write CSS, or a horrible class soup, depending on your opinion of utility classes.
Thanks, that's a really clear answer. Now it's got me scratching my head. I like not having to make a lot of decisions, hence my affinity toward BS. But TW might be worth a spin.
Bootstrap is a fully opinionated framework, tailwind is far more versatile, it has his opinions, but they aren't set in stone in the way that bootstrap is.
You can build bootstrap in tailwind, but you can't build tailwind with bootstrap.
Both are tools to help you design something, but the tradeoffs of each one are quite different.
Inline css is very powerful, but tailwind gives you the vast majority of that power with a much smaller learning surface, and with the ability make sweeping style changes without having to update the css in every single component.
What happens if I have 20 of these divs and need to modify py-3 to py-4? Can I create a "local" .css file to "group" these tailwind classes ala pseudocode below?
If so, then the div becomes <div class='divxyz-default'>. A thought came to mind that in that case I have gone back to CSS modules but then we still have some benefits of standardized classes e.g. instead of specifying how much roundness, I am using standard amount of roundness via "rounded-lg" and if I want to change that globally, I can edit in one place. I am probably missing something.
Yes, you can use Tailwind utility classes within your own CSS files. The Tailwind syntax for creating custom classes is @apply. Here's how they recommend approaching the problem.
I find @apply useful for styling HTML that I don't directly control, such as rendered Markdown. Otherwise, I do prefer Tailwind's suggestion to use templates/components instead of custom classes, wherever it makes sense.
despite a lot of the backlash i've seen around the web concerning tailwind, bootstrapping projects is easier when all* the work is done for you. i also found that the consistency and familiarity you gain is just... nice? i've learned a lot about css through the tailwind documentation, and it's impacted the way i look at and implement my own css outside of using it. i even practiced learning css by creating my own design system / atomic css framework by mimicking tailwind. not sure if you've checked this out but windicss[0] is an awesome implementation of tailwind.
Not everyone is working at even 1/10th Google scale. Most aren't working at that scale. The vast majority of sites and web apps can get away with a relatively minimal amount of CSS and modern CSS features in a one or a few concatenated files. For the rest of us, tools like Tailwind, SCSS, etc., are best treated as tools to help us be more efficient, and they are not necessities.
If basic CSS doesn't "scale", then it's time to stop and think about whether one is doing the right thing.
CSS stops being scalable much earlier than 1/10th Google's scale. Without rigorous practice, CSS' idiosyncrasies start getting in the way after 50 lines of it.
Author here, I just looked at our frontend build and Create React App bundles our CSS into one big {webpack-hash}.css. It scales well for us because the frontend is a single page app.
i mentioned this in another comment but one takeaway i got from using tailwind is that it changed the way i look at css. i use it as a learning tool as well, which is something i rarely ever get out of solutions that try to do most of the heavy lifting in a project.
consider this comment an open-invitation for other good css references!
i've heard a lot of great things about this course. like, a lot. i'm pretty broke so most of my money goes towards tuition and rent, maybe i'll ask for this for christmas!
i would say the tailwind docs themselves and looking at the examples were a big help. for instance, the way they visualize their flex elements was enlightening. also, learning about how atomic css is a useful paradigm was the biggest motivator for writing more meaningful and expressive css. i'll list some things i've bookmarked:
and finally, it's always useful to read critiques. the following article is well written, in my opinion: https://www.browserlondon.com/blog/2019/06/10/functional-css.... through that i learned that tailwind has a useful feature: @apply, which you can use in conjunction with a standard css class approach. i.e
container {
@apply color-grey-100;
box-sizing: border-box;
}
I don't get why you wouldn't use LESS mixins or SASS class extensions (or whatever the modern equivalent of that is) instead of inlining each utility class directly into each div.
Having a name for each element in your markup is really powerful and useful, and it seems like the Tailwind approach exists specifically to avoid having to name things.
I think the thought process is that if you are using Tailwind it's probably with a component based system like React. So you don't need a button "name" because you have a button component. You re-use components instead of classes.
This makes it so you don't have to remember all the names specific to the project (or learn an existing projects css names).
I've never used Tailwind myself so I am not advocating it per say, just explaining how I understand it.
Embracing components over classes is what helped me understand and appreciate functional CSS (Tachyons, Tailwind, etc). Lots of headaches removed when the DOM structure finally 1:1 reflects the style inheritance structure, without having to maintain the latter separately.
Exactly. When using something like React, the abstraction of using classes to create reusable components is redundant with the framework's, and thus no longer carries its weight. Especially considering how, in practice, that abstraction isn't that effective in the first place: it's rare that a layout change involves just a CSS change. (I'm somewhat rehashing from a blog post of mine [1] here - if anyone wants this more extensively argued they can read that.)
Also you avoid writing CSS and designing like before CSS existed. Its more messy but a bit easier to learn then CSS. CSS is simply too advanced and powerful it takes years to master. Ohh and you can copy/paste components into your spaghetti code.
>Also you avoid writing CSS and designing like before CSS existed.
I know this is controversial because of the web dev canon of "lol CSS sucks", but many people really love CSS, and find it incredibly powerful and enjoyable to use. If you put in the time to truly learn it, these tools seem silly and redundant.
In my experience you tend to end up in a weird thought experiment trying to work out what the third child of the body of a card should be called when actually you just want it to be bold with some padding.
As other people have said, naming things also becomes totally redundant when you’re using something like React or Vue where the abstraction is a component which is itself already named.
Author here, I have a few custom classes that look like more traditional CSS. Tailwind gives an example[0] of how to do this in their docs. I have about 15 of these extracted classes. I use them for common styling patterns, such as transforming "flex items-center justify-center" to "flex-center," or to unify styling on components I haven't abstracted into a styled version, such as "listbox-option" or "flyout."
I have used Tailwind and IMO it is a bad solution for most non-trivial web projects. I won't bore you with details because this is the internet. Be honest, you would skip this comment if it was a five paragraphs.
Personally I don't mind that Tailwind exists. To each their own. My issue, as another commenter pointed out, is the marketing. The more popular it gets the more often I get stuck working on a client's app that uses it because someone thought it was the best thing ever. It's not. But that person has left the company to make another mess. Job security I guess.
I disagree. I've worked on some pretty beefy projects with both "traditional" CSS and Tailwind. Granted, Tailwind isn't that old in the grand scheme of things so trying to fit it in to legacy projects (5+ years old) can lead to different outcomes.
With the old CSS paradigm, I find most of the time you get into a rut where old styles can't be deleted for fear of breaking some obscure part of the experience that development has stagnated on in recent times. Your CSS file continues to grow as new features are added and the old stuff is never reexamined or removed. Who's to say that `P { margin: 0 auto; }` isn't implicitly being used on code being written today?
With Tailwind, all of that ambiguity goes out the door (especially with the JIT becoming the default in v3 at the end of this year). If I remove some classes in my markup, I can be confident the CSS file that is generated is optimized to only include what I need and I'm not saving any old cruft. That alone is a huge boon to confidence and productivity. If I don't have to audit old CSS, that's a win. I don't need to think about old CSS during code reviews, etc etc.
The other part I find most useful is the elimination of generating novel class names, but I will concede that isn't a problem for everyone. Personally, I find that sort of stuff mentally taxing in a way that I don't enjoy.
Finally, I feel like something nobody tends to talk about is that the real power scenario for Tailwind is when it's paired with a framework like React/Vue. The duplication problem is resolved by components that are meaningful to your app, not by arbitrary CSS classes. If I'm repeating the same class over and over again, that's a clue that there is likely a UI component to be extracted. These components also aren't limited to frontend frameworks; nearly every templating language supports partials in some flavor.
I'd be interested to hear your full write up. I believe you've experienced pain, but I wonder if in these conversations were are talking past each other or there is some other external variable that the other party is not aware of.
For example, at my day job, I do a lot of custom enterprise-y WordPress development. Tailwind is a pretty awful experience to work around in the current WP paradigm. I can relate with teams who may have tried to work in a similar scenario.
Tailwind isn't going to solve every problem, but I do think it can provide a lot of structure to teams out of the box with very little configuration, and that is it's primary value add imo.
A Design System makes sense. It's the UI SME if you will.
That said, in that context, I don't see the appropriateness (?) of something such as:
.rounded-lg{
border-radius: .5rem
}
It's not abstract enough (for me). That is, if the design system evolves that shouldn't become a code issue (e.g., remove .rounded-lg and replace it with something else). To me all that should be via CSS and only CSS. There sould be -as much as possible - a layer of abstraction between the code and the design system.
Is it just me? What am I mis-thinking? Or does CSS in JS all but eliminate such a possibility? But isn't that what a design system helps to resolve?
For the vast majority of components, don't you think some small-medium-large presents cover most cases? This applies to so many style areas- typography, spacing, colors... For edge cases, there's nothing preventing you from overriding the style.
functional css is basically anti design system. Some will deny it and claim that they do have a design system implemented in functional css, but really all they do is adding a redundant layer between css and their design system.
What do you mean? There is nothing special about naming classes and grouping styles together that is exclusive to a design system.
I work at a well-known tech company and we have many projects using the same Tailwind configuration, and an entire components/ file with .jsx components. No need for making up arbitrary class names.
in a design system no reusable classname is abitrary, they should all mean something in your design language. If you find yourself reusing arbitrary classname, then that's just... writing css, not using a design system.
the idea of the design system is that you compose from what in your design system exclusively. This is to prevent ad-hoc slyling that goes outside established patterns. If you are just going to compose generic css then there is no point.
I never had to name any class because I use styled-components. Either the style is part of my design system, then it has a name, the component name, or it's just ad-hoc css, that I don't export. I don't reuse that kind of thing.
The tailwind way is you try to reuse & compose bits of the ad-hoc css by having generic, arbitrary classnames that you don't write but provided by a library
I wanted to like tailwind, but the html/tsx became so bloated and unreadable that I actually begun appreciating scss modules more. Separation of concerns and all that jazz.
People often tout "separation of concerns" but it really doesn't apply here.
The important concerns to separate are business/application concerns. Putting your JS in .js files, your CSS in .css files, and HTML in .html, it's separation of languages. You could argue that the three languages solve different problems but this isn't true. We have JS writing DOM nodes which HTML does intrinsically, we have CSS and JS doing animations, we have CSS that does styling but also CSS that does layout, HTML nodes that are sometimes there specifically for design or layout concerns. We should be focused on components here, which use the three technologies to solve one business/application problem.
Tailwind can get a little ugly, but you are supposed to use it in conjunction with components. Personally, I don't find 10 inline classes that much harder to read than 10 style rules on 10 lines.
I'm not the person you were replying to, but I kind of treat @apply as an anti pattern. It exists purely to satisfy some a "need" for "clean code".
After a week or two w/ Tailwind full-time, the verbose syntax fades into the background and it's a problem in practice. I've been through a few teams who came into it very skeptical but all conceded it wasn't a problem after becoming acclimated to the paradigm.
My uncompiled CSS file is usually less than 50 lines, with the bulk of that being some sort of one-off animation or gradient syntax that Tailwind can't do out of the box.
Utility classes are an absolute nightmare. I get that for people who can't or don't want to put in the time to master CSS that they can seem really useful at first. But they are a total headache for long term maintenance. By loading up the classname attribute on an element with tons of utility class names, you are defacto creating a new class that is equivalent to the hash of all those names. You're better off just creating the class in the first place and giving it the properties it needs. Maybe use SASS mixins if you really want code reuse in your CSS that badly. But the next developer who comes in to debug a component now has to learn an entire design system and the intricacies of how the 10 different classes you've applied all work together, instead of just looking up the class definition and fixing the issue.
I genuinely don't see how you think it's more difficult to debug class="bg-blue flex items-center" versus class="SpecialBuggyComponent" and then having to cross-reference and dig through a bunch of styles in a css file.
>I genuinely don't see how you think it's more difficult to debug class="bg-blue flex items-center" versus class="SpecialBuggyComponent" and then having to cross-reference and dig through a bunch of styles in a css file.
Because it's never just 'class="bg-blue flex items-center"'. It always becomes 'class="bg-blue flex items-center text-base font-sans font-medium rounded-lg bg-gray-100 text-black py-3 text-center cursor-pointer"'
And now I'm spending 20 minutes digging through every single one of those classes to find the reason my 2 lines of added CSS for this ticket won't apply without an !important.
What is it that you find confusing about each of those class names though? They're certainly more descriptive than "SpecialBuggyComponent", and it should be easy enough to infer what each of them does even if you're unfamiliar with tailwind.
The verbosity was a turn off for me as well until I found eslint-plugin-tailwindcss which enforces predictable class ordering, making those long strings much easier to understand at a glimpse.
So the utility class lists become so long, tangled and unmanageable that we write software to order them in a predictable way and make them somewhat comprehensible and more manageable.
Does this not raise a red flag?
I know I’m probably a dinosaur using SCSS, BEM and ITCSS but I find my code based logical, tidy and a pleasure to work with.
I do have the tailwind color and spacer presets as variable maps accessible via short functions so I can say color: c(yellow-500); in my SCSS and have all the benefits of standardized colors, spacing, font sizes.
Either way, you've had to dig through styles; the difference is that Tailwind keeps the styles at the component level, without the arbitrary naming and additional file requirements that traditional CSS classes introduce.
Author here, I haven't had time to play around with it, but this library[0] from Atlassian looks like a "best of the both worlds" styling approach: CSS-in-JS authorship without the runtime penalty.
If you like the idea of tailwind and don't want to look at utility classes and still want the power of styled-components or react-emotion I'd check out Chakra UI [0].
The tooling is much less intertwined with other tooling and therefore less likely to cause problems, and the runtime performance impact is less. That's pretty neat.
the syntax of styled-components plays so nicely with actual reusable components. A mesh of tailwind syntax with reusable components feels weird. But mostly, a div with 10 classes each doing one small thing is so unreadable
I doubt the parent is talking about applying each of the tailwind util classes directly, but instead wrapping that combination of classes up into a reusable component to be applied around.
They're talking about the @apply directive. It takes a list of classes and creates a single class with those properties. Since Tailwind classes generally map almost 1-to-1 for CSS rules, it'd be easier in my opinion to just write the CSS directly.
I'm fully aware of what they're talking about. It's common usage in Tailwind to extract large collections of the utility classes back into reusable component classes which can be applied with a single @apply directive [1]. This being the case, this would not be a 1-to-1 mapping at all.
I still don't get CSS in javascript. Why blow up the size of the payload when linking to a compiled style sheet is sufficient? Yes, I realize some components are one-offs, but I think the discpline required to keep CSS clean is a small price to pay for mitigating bloat.
Tailwind isn’t css in js. It’s just css. They’ve built endless css mini classes that effectively give you enhanced inline styles. So stuff like hover variations are possible by adding the class directly to your element.
You can use the just in time compiler to generate the classes on the fly rather than importing millions of them in as a style sheet. That’s js, but really it’s just a regex that scrapes things that look like tailwind class names from your html and generates those classes for you.
Ah, gotcha, the theme stuff at the bottom? Yeah, I don’t like that myself. I’ve been there with materialui and it’s depressing seeing runtime css kill your js performance for absolutely no gain.
I honestly thought Tailwind is a sarcastic project mocking bad css class names until I found the Windi.css fork which has now inspired Tailwind JIT and it 'clicked'.
Writing class="<md:content-center sans font-normal hover:font-semibold pt-[7px]" and having a media query for phones, proper flexbox centering, font face and weight stuff autogenerated without copy pasting and googling snippets is amazing.
And you can reuse the same thing in any project without setting up imports and build steps and being constrained to a specific component framework. No selector specificity/namespace conflicts, just pure WYSIWYG.
I've been using CSS Modules as well as Shadow DOM for styling for about 2 years now after ditching SCSS. I've switched over to using Shadow DOM and things like Constructable Stylesheets, but CSS Modules is still one of the best options for compatibility and ease of use (no boundary restrictions being the main one).
I've tried to like TailwindCSS. I tried to use it on a project and I just found it so complicated and messy. People are quick to say, "Oh, give it time, eventually you don't need to consult the documentation as much" which is a strange thing to me, because for normal CSS it's rare I do have to consult MDN to know something (unless it's CSS Grid syntax). If you're new to Tailwind be prepared to waste hours just consulting documentation until "it clicks". You're basically learning a new language on top of CSS. And then the resulting markup in some Tailwind apps I've seen isn't easy to read, it ends up being no different than the randomised classes that CSS Modules gives you.
CSS Modules work perfectly with design systems and other CSS additions. I even use CSS Modules with Bootstrap 5, it works well.
I'm not saying Tailwind is bad, but there is a curve when you use it. It' also feels very boilerplate-y, which I know the React crowd loves, but I don't work with React. Given the amount of work I have on my plate, I would rather stick with my current approach than lose hours in productivity because I want to change how I write my CSS.
For me reading documentation is the major part of the development process and having a good experience and a reduced palette of options helps a lot. I have used css for years but never really learned it properly. I would spend ages trying to debug issues on various css documentation sites. I find that tailwind just has a solution for everything and I rarely need to go outside the Tailwind documentation. I think it helps develop your way of thinking. And one day I might grow out of it and return to normal css with a better perspective. Obviously I should just go an learn CSS properly, but I probably won't.
How did you learn the CSS properties without consulting documentation? I get that you don't need to consult MDN every _now_, but imagine you were just learning. You'd likely need MDN very often. I still consult MDN for the syntax of some of the more advanced properties.
Yeah, the difference is that once you know them, you can use them on literally every project until CSS somehow gets replaced with something else (which will never happen).
If you put all that time into learning the tailwind shorthand then you're fucked on the next project that doesn't use it.
Personally I'd prefer to not have to re-learn how to style things on every damn project just because some noobs that have to pay the learning cost anyway think they've found some 5% efficiency with some shit library.
Do you also not learn new programming languages for fear of not using them on the next project? Your words are really aggressive. Try to have a more open mind.
Author here, CSS variables change the landscape in terms of what is possible. I think Theme UI (CSS-in-JS) uses them heavily under the hood. I can't think of the name, but I saw a CSS framework on HN some months back that is almost exclusively CSS variables. Plenty of unexplored territory there.
The original point of CSS was to remove style code from HTML. This made a ton of sense twenty years ago. Web content was often saved directly to static files, so imagine having to update styles across hundreds of HTML files manually without VS Code.
Tailwind seems like it could be very useful if one's UI is strictly component based. Otherwise it seems like a portal back into writing HTML on Windows 98 using notepad. Either way, thankful for innovation and more options.
Not sure why, but I thought Tachyons CSS was kind of the first to take this approach, but Tailwind certainly caught on much faster event though they came on the scene over a year after Tachyons:
Tailwind has amassed 21.8k stars on GitHub and it is being used by 38,749 repositories and has over a 100 contributors, it also has 73,791 weekly downloads on NPM.
Tachyons has 9.7k stars on GitHub, has 64 contributors, and has 26,384 weekly downloads on NPM.
what about bootstrap or whatever came even before that?
all these libaries do is adding more to that fundamental idea, nothing is conceptually new here.
I notice in the config you specify "colors" and "fonts" but also "fontFamily", not plural. Ugh. I hate inconsitancies like this. They make it a lot harder to predict how to specify what you want, and it's likely that someone in the future will "fix" it and you'll end up with deprecation warnings all over the place.
Creator of Tailwind here — what you're seeing here actually is a best effort attempt to be consistent and predictable.
Keys in the config file generally correspond with the CSS property they refer to, and we use the singular form to make it match the CSS property.
There are 3 exceptions, which are "colors", "spacing", and "screens", and these are sort of special keys that don't map to anything in CSS. The "colors" and "spacing" keys are more like reusable variables that are consumed by the property-specific keys like "backgroundColor", "fill", and "borderColor" in the case of "colors", and "width", "height", "gap", and others in the case of "spacing".
The "screens" key is a list of breakpoints for your project, which also doesn't map to an underlying CSS property.
Originally we tried to keep things really abstract and group things together under concepts like "spacing", "typography", whatever, but ultimately found it was more flexible and predictable to make it possible to customize every CSS property using the exact property name, while only providing a couple high-level things like "spacing" and "colors" that you can use to update other dependent keys at once.
Getting complex config files right is unfortunately hard and it's not perfect for sure. At this stage in the project it's a delicate balance between improving things and maintaining backwards compatibility. Totally appreciate what you're saying, just wanted to do my best to clarify though as I'm equally picky about this sort of consistency.
I can understand non-CSS things being different, though it still feels wrong to have them plural when nothing else is, but then... "spacing"? Why isn't that plural, when the other 2 are?
I appreciate all the work that goes into something this large, but that just makes me more sad that this jumps out at me so quickly when I look at the examples. This kind of thing made PHP a laughing stock for many, many years before they finally bit the bullet and standardized their function parameter order, etc. And I say that as someone who does PHP for their day job by choice. (Among other languages.)
Tailwind is mostly consistent, but I do sort of wish it were color-gray-500 instead of text-gray-500, and I think some of the sizes are a bit confusing in terms of when you can use what.
What would you do if backwards compatibility were out the window?
Author here, I will add my kudos for the Tailwind API. The more I've used it and internalized its structure, the more I appreciate the care and effort of its API.
That's because fonts is a collection of the singular font. Colors, the same for color. fontFamily is precisely what is says; a font family. It's a singular unit. There is no inconsistency here.
When configuring the settings, it uses `fontFamily`, singular, to set up multiple font family options (eg. options for "heading" and "body" in their example). `colors`, however, is plural here.
When applying them later in the code, they're both singular since they're specifying a specific family/color.
I agree with GP that this inconsistency shakes my confidence in the package.
Tailwind is free and open source. If it really shakes your confidence with the entire system, you could certainly consider opening a discussion or PR. I've been using Tailwind in production and I never even really thought about it. It just seems out of place that of all the incredible work Tailwind is doing, this potentially minor issue is enough to say "well then nevermind".
The above line of markup looks like utter crap tbh, not to mention, the fact that it's a div vs the name of what you consider it to be in the context of the other objects on the page seems like you're obfuscating its role. I just don't think it's a good thing to use unless you're doing a bunch of one offs that you'll never have to support.
As someone who's been doing frontend work for 10+ years, Tailwind is great.
Over my career I started by using global CSS files, transitioned to CSS modules, then to styled-components. I never touched Bootstrap because it was clunky, ugly, and annoying.
Creating layouts and styling everything consistently has always been a pain in the ass. There'd always be some element that I decided to style differently, or break out of the "design pattern" just because I needed a one-off or it didn't fit well. On some projects I spent the majority of my time trying to organize styles so that I could remain consistent and handle edge-cases "well enough" that everything was still clear and legible.
The first time I saw someone using Tailwind I immediately thought "ffs not this Bootstrap garbage again", but I decided to roll with it because it wasn't my project. Since then I've been using Tailwind for all of my projects.
When you combine Tailwind with React, you get nudged into creating a library of components with default styles (ie. a design library). If you need to change the styles for certain instances of the components, you extend the component itself and apply styles according to flags (using classnames utility). If you need more control in certain situations, you use inline styles.
What this means is that Tailwind actually fixed my problems with styling consistency and organization, and made me better at writing re-usable React components.
Yes, the className prop can get long, but you can use the classnames utility to break it up into separate lines (and organize the classes however you want). Testing different styles for components becomes a lot easier too once you memorize the class name patterns that Tailwind uses. It quickly becomes legible and you can usually guess what the class name is for whatever style you want to add.
Still, I hope Tailwind can improve on this somehow to remove the remaining issues (legibility for beginners, and the long-ass className prop)
@set my-component {
:root { background:red; } /* the component itself */
:root > header { background:gold; } /* its content */
:root > footer { background:var(footerColor,#0F0); } /* use of vars that can be set in JS too */
}
As someone still sometimes building brochure-style sites, I do wish it were easier to componentize things without unnecessarily turning every site into an SPA with React et al.
I've recently discovered Tailwind, and after a day or two of getting used to it, not only does it 'feel' more natural when styling than what I've used recently, it also opens up a lot of doors for performance. Speaking from a traditional business website stack perspective (non react).
There is nothing preventing anybody from using design systems with CSS Modules.
The author makes it sound like you need stuff like Tailwind in order to leverage design systems. This is completely misleading.
> I have used Tailwind UI as a starting point and inspiration for my own components.
There are loads of UI libraries you can use as a starting point & inspiration with CSS modules as well.
The concept of a design system is orthogonal from one's styling solution of choice (CSS modules, Tailwind, CSS-in-JS).
The author certainly knows how to write a blog post and does a good job at selling Tailwind. But in my opinion he doesn't have enough experience to give this kind of opinionated advice to others yet.