13 ms·
Don't use Tailwind for a design system (2021)
- brnewd 4y agoI'm still firmly in the Bootstrap camp. It's boring, well understood by the average website visitor. Allows for rapid development and thereby time to market. I tried Tailwind once, but found the added complexity not worth the trouble. I guess it all hinges on the type of project(s) and runway.
- efields 4y agoor do. It's fine, really. None of us are your mom.
- thinkxl 4y agoThis is how we do it. We don't use Tailwind directly on your components (unless necessary and for adjustment only, more on this later). We try to keep Tailwind as an internal implementation detail. The consumer of our components should pass options as `variant="primary"` where `variant: "primary" | "secondary";` BUT it's okay to allow some Tailwind classes for customization on edge cases. Example (by memory, syntax might be wrong): import cn from 'classnames'; // Definition function Button({ fill, isLoading, className }: ButtonProps) { return (<button className={cn( 'relative', 'inline-flex', 'rounded', { 'w-full': fill, 'opacity-50': isLoading, }, className, )} > {children} </button> ); // Usage // Full-width button, with some margin on the left <Button fill className={"ml-2"} /> // Regular button, with loading state <Button isLoading /> You can even go further and use https://github.com/crswll/clb https://github.com/crswll/clb and create your own rebassjs.
- chris_st 4y agoInstead, consider using DaisyUI[0] as a design system, which is built above TailwindCSS. As a bonus, it's just styles, so it works with any JavaScript system (or none). 0: https://daisyui.com/ https://daisyui.com/
- rmckayfleming 4y agoPretty 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.
- xkcd1963 4y agoYes, this is the typical reinvention of the wheel, where junior devs (all for the right purposes) want to learn by implementing their own version. But mixed with the hipster culture of everything new is automatically better and you get discussions like that.
- redbar0n 4y agoThe author's gripe with using Tailwind with components is more concretely expressed in this follow up thread: https://twitter.com/davesnx/status/1329392089189265408?s=20&t=yL1Q2zepqxG1ihgn_-PyDQ https://twitter.com/davesnx/status/1329392089189265408?s=20&... For reference, this is how Tailwind suggests using it with components (aka. "component-driven" as it says, which the author takes issue with): https://tailwindcss.com/#component-driven https://tailwindcss.com/#component-driven I think the gripes come from trying to combine the bottom-up approach of Tailwind with the top-down approach of props based styling that JS component libraries typically allows. His point being that Tailwind does not work too well with such solutions for dynamism / contextual style overrides. You could solve it with using clsx or cva though, as seen in this video: "Tru Narla: Building a design system in Next.js with Tailwind" https://www.youtube.com/watch?v=T-Zv73yZ_QI https://www.youtube.com/watch?v=T-Zv73yZ_QI The best way seems to be making styling a completely internal component concern, and not take in style props but simply semantic props like isActive=true and then have the component itself apply styles based on that, like NavItem.js on the Tailwind home page suggests: https://tailwindcss.com/#component-driven https://tailwindcss.com/#component-driven This practise is elaborated in this example, that has the same button styled differently by passing in different semantic props: https://youtu.be/T-Zv73yZ_QI?t=570 https://youtu.be/T-Zv73yZ_QI?t=570
- ls15 4y ago> @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.
- deleted 4y ago[deleted]
- nonethewiser 4y agoProbably 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.
- EduardoBautista 4y ago> 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 https://github.com/ben-rogerson/twin.macro
- dimitrisnl 4y agoI'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.
- stefanfisk 4y agoConcatenating 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 4y agoI 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 https://www.npmjs.com/package/classnames
- vehemenz 4y agoA 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.
- satvikpendem 4y agoI'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 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.
- akvadrako 4y agoAttributify 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 https://windicss.org/features/attributify.html
- redbar0n 4y ago
- danielvaughn 4y agoThe 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 4y agoAgreed. 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 4y agoThe 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 4y agoI've found VS Code's Tailwind intellisense to be unreliable. Half the time it just doesn't generate anything.
- simonsarris 4y agoPress Ctrl+spacebar when typing to explicitly invoke it
- jamager 4y agoYes!, Jetbrains works very well to.
- caporaltito 4y agoThe guy is not happy because he still has to write CSS from time to time, yet says the classes from a CSS utility library, which prevent him from having to write too much CSS, should be thrown to garbage. Another absolute title article to make you click.
- johnrackles 4y agoThis code example is explicitly not supported in tailwind: const className = "p-" + props.gap.toString(); according to https://tailwindcss.com/docs/content-configuration#dynamic-class-names https://tailwindcss.com/docs/content-configuration#dynamic-c...
- HuwFulcher 4y agoI 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 4y agoI 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.
- meet_zaveri 4y agoStarted 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 4y agoWe do the same and haven’t had any problems mixing antd and tailwind
- neximo64 4y agoThese sound like gripes with React more than tailwind.
- redbar0n 4y agoI think they are gripes from trying to combine the bottom-up approach of Tailwind with the top-down approach of props based styling that JS component libraries typically allows. His point being that Tailwind does not work too well with such solutions for dynamism / contextual style overrides. You could solve it with using clsx or cva though, as seen in this video: "Tru Narla: Building a design system in Next.js with Tailwind" https://www.youtube.com/watch?v=T-Zv73yZ_QI https://www.youtube.com/watch?v=T-Zv73yZ_QI The best way seems to be making styling a completely internal component concern, and not take in style props but simply semantic props like isActive=true and then have the component itself apply styles based on that, like NavItem.js on the Tailwind home page suggests: https://tailwindcss.com/#component-driven https://tailwindcss.com/#component-driven This practise is elaborated in this example has the same button styled differently by passing in different semantic props: https://youtu.be/T-Zv73yZ_QI?t=570 https://youtu.be/T-Zv73yZ_QI?t=570
- simonhamp 4y agoI have to chuckle a little at these posts that seem to be 'upset' that Tailwind (or some new framework du jour) is not the silver bullet that the hype train has had them believe I love Tailwind and use it daily, have done for almost 6 years now and I haven't experienced any issue I couldn't solve It certainly has never got me thinking to just throw it away or denigrate it publicly. And my solutions have worked well in a team setting - not adding any burden to other devs This feels more like it's at the intersection of React-specific problems and lack of experience with Tailwind and/or CSS in general I can see some of these problems being frustrating, but because the author seems to just be sounding off without much effort to express attempted solutions, I'm flagging because I feel like this is just anti-Tailwind inflammatory BS Edit: Title also needs to indicate this is from 2021
- redbar0n 4y ago> but because the author seems to just be sounding off without much effort to express attempted solutions, I'm flagging because I feel like this is just anti-Tailwind inflammatory BS On attempted solutions, there was a subsection titled: "What should I use instead of Tailwind for my design system?" He also suggested this solution for Tailwind, if you read it carefully: "If you still like what Tailwind offers, I recommend a similar approach that we do at Draftbit. Create a tiny layer on top of it: Treat all the Tailwind tokens as code and maintain Tailwind scoped inside those components. Abstract those utility components that you found repeated in your code into a more strict version, and minimise Tailwind for your app." The post was arguably not inflammatory, but pointed to specific issues with Tailwind viz-a-viz design systems. The points raised may not be correct(?), but that doesn't mean it's inflammatory BS. > Edit: Title also needs to indicate this is from 2021 Good point. Updated.
- pvg 4y agoUpdated. You don't need the month, the HNconvention just uses the year in parens and some things rely on that format.
- simonhamp 4y agoI said "I feel like"... that's just how reading the article made me feel I think if it was really intent on providing a clear argument, the author would have gone to a little more trouble to show their work and taken us all on the journey As they didn't, I'm not convinced, and the fact that it's made its way to the top of HN suggests there's just a bunch of anti-TW up-voters ready to jump as soon as there's a whiff of some apparently-new reason not to use it Kinda disappointed this article got shared again tbh
- esskay 4y agoTailwind isn't component-driven, which they claim to be Stopped reading there. It's a utility library, that much has always been blatently clear and obvious. Really poor article.
- redbar0n 4y agoFWIW here is the author's backing for that claim: backing: https://twitter.com/davesnx/status/1329407408922370050 https://twitter.com/davesnx/status/1329407408922370050 claim/thread: https://twitter.com/davesnx/status/1329392089189265408 https://twitter.com/davesnx/status/1329392089189265408
- redbar0n 4y agoI also found this section on the TailwindCSS landing page...: > Component-driven: Worried about duplication? Don’t be. ... https://tailwindcss.com/#component-driven https://tailwindcss.com/#component-driven
- noselasd 4y agoThe way i read that is that "if you are using Tailwind in a component based framework, do e.g. this ...". Which is entirely different thing than saying "Tailwind is component driven".
- plaguepilled 4y agoGave up halfway. I try not to nitpick on grammar and spelling, but this article's lack of editing legitimately makes the reading experience unpleasant.
- sonicgear1 4y agoPlease 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 4y agoThe 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 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 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 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.
- deleted 4y ago[deleted]
- mellosouls 4y ago[flagged]
- deleted 4y ago[deleted]
- pvg 4y agoIt's OT enough to have its own site guideline, yes.
- mellosouls 4y agoI'm aware of that site guideline; most articles aren't specifically advising on UI choices though.
- stevev 4y agoSounds more like it’s a react problem. I use vue.js and I don’t have these issues.
- jFriedensreich 4y agoi am thinking about a feature that works like a reverse apply. instead of compiling the tailwind classes into the css class that uses apply, it would add the applied tailwind classes to the html class. this way all the tailwind optimizations and workflows would still work, but at least a few of the problems can be mitigated.
- newbieuser 4y agotailwind is a library I don't like in many ways, but the criticisms in this post are pretty ridiculous. tailwind is not a library offered with the motto of component driven as the author mentioned. and instead of bloated packages like radix ui I think it's a more sensible solution. at least it gives a chance to follow a more optimal path. I think it is impossible to find an optimal way with the libraries it recommends. you should use everything just as the library intended.
- redbar0n 4y ago> tailwind is not a library offered with the motto of component driven as the author mentioned. I thought Tailwind shined the most when used within components (and why it's become so popular with React).. making components and not CSS the nexus of abstraction. > and instead of bloated packages like radix ui I think it's a more sensible solution. ... I think it is impossible to find an optimal way with the libraries it recommends. The author recommends ThemeUI, Rebass, Stitches and/or Radix for design systems. They might add undue bundle size, to various degrees. But a recent and very powerful (close to as optimal as possible?) alternative is Tamagui which takes inspiration from all of those. All for the cost of some 20-27 kB, apparently with a clear path to come below 8 kB in the future: https://tamagui.dev/blog/version-one#bundle-size-reduction https://tamagui.dev/blog/version-one#bundle-size-reduction
- manxman 4y agoIs 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!
- sodapopcan 4y agoThis is the same repeated criticism that gets repeated over and over and over again about Tailwind. It's misguided and getting a bit tiresome.
- manxman 4y agoI agree it has a place for rapidly prototyping a design. But it pukes in the face of the “DRY” principle and wouldn’t keep it around in production. Use it to get the look right, take the styles and abstract to a sensible place in the design system or component hierarchy passing in the values so you can change one thing not a load. Just following the idea that making life easier for yourself six months from now when you don’t have the current project “context” in your head is way better for lowering technical debt. Oh and we will probably be into another fashionable styling framework by then! ;-P
- sodapopcan 4y agoIt's been explained in many blog posts as well as in the Tailwind documentation itself. It's meant to be used with components (or partials). There's no copy-pasting involved and is very well-suited for production code. And this applies to any utility-based CSS framework.
- dubcanada 4y agoThis 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.
- firemelt 4y agothat is javascript programmer they think everyone write javascript
- zmxz 4y agoThis 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 4y agoI'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
- deleted 4y ago[deleted]
- nerdywordy 4y agoNo, 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.
- moneywoes 4y agoHow about MUI
- deleted 4y ago[deleted]
- T3RMINATED 4y ago[dead]
- hakanderyal 4y agoI'm going the opposite way and switching from CSS-in-JS to Tailwind. While I like the css-in-js way of doing things, React seems to be moving away from runtime css generation, and I'm not sure the ecosystem will catch up (and I'm tired of playing catch up). Sticking to CSS guarantees you won't have any compatibility problems.
- redbar0n 4y ago> Sticking to CSS guarantees you won't have any compatibility problems. Unless you attempt to go cross-platform.. There are many attempts at getting CSS working on React Native for instance, and many have various compatibility problems (especially as they need to keep up with the evolving CSS spec). But if you do go cross-platform, then something like Tamagui is probably a better bet than trying to replicate CSS. You could also try Nativewind, to get the Tailwind benefits (and limitations, like lack of support for animations).
- hakanderyal 4y agoI don't need native and web compatibility, so no problems on that front. Tamagui is on my radar, but it's too new for me to give it a try with my limited time budget.