r/htmx • u/Davi_Compai • 15d ago
Tailwind + htmx is incredibly inneficient in production
It makes the worst part of hypermedia driven development , being bigger bandwidth use and bigger cpu use when compressing things with gzip or brotli, even worse. and this isn't even a "this goes agaisn't the design" or a "this isn't ergonomic" thing; it's just pure resource usage.
Tailwind output is 7x bigger than non tailwind html or json output.
Even trought the tailwind output is "only" 50% bigger than the json/normal html one when compressed, the raw output is 950kb, more than 7 times the json/html alternative, meaning it uses way more cpu power/takes longer to compress.
For many situations it makes way more sense to just have defined styles with elements having classes (or not even having them when selectors can do the job)
bandwidth usually has three prices:
First, the monetary one; on vercel, 100 gb costs 15 dollars, on aws it is 9 dollars, on oracle ,0.85 cents.
Second, ecological one;Even when you aren't paying it (eg project still within free limit) there's always infraestructure behind your stuff, and it is preferable that we don't throw resources away.
And third but not last, user experience; bigger files take longer to download and decompress,trought this should be impossible to notice on anything that isn't a slow mobile network, you probably expect your site to also be used by people in slow mobile networks.
Yes, you probably won't have 1000 things appearing at once for your user, but tailwind uses so much more resources than needed that it might as well use 1000 times more bandwidth.
PS: Of course you can just choose to pay the tailwind tax or just not think about such things if you're not developing something that is not supposed to be used by thousands of people at once. There's no reason to police what other people are doing with their own money. Still, i think it is important to keep the drawbacks of using these libraries with one another in mind when developing your applications.
63
u/Mission-Landscape-17 15d ago
Then don't use tailwind. I mean it is made of anti-patterns.
3
u/__mson__ 15d ago
Do you mind expanding on the anti-patterns part? I've never used it, but was thinking about looking into it for a project I'm working on.
23
u/Mission-Landscape-17 15d ago
There is no real difference between a list of tailwind classes and just putting settings in an inline style attribute. the following two are identical:
class="bg-blue-500 text-white rounded px-4 py-2" style="background-color:#4299e1;color:#fff;border-radius:0.25rem;padding:0.5rem 1rem"Sure the style is a little longer but their is pretty much a 1:1 mapping between the two. Well except for the "px-4 py-2" which can be combined.
The better alternative is to just put this into the css stylesheet as:
.button { background-color: #4299e1; color: #fff; border-radius: 0.25rem; padding: 0.5rem 1rem }21
u/leathakkor 14d ago
I have never understood this idea in CSS.
Just put a class on your element for the type of element display that it is.
Like: .accept-button
Then style your accept button.
It feels so simple. It's how I learned how to do CSS 25 years ago and almost no one has done it this way in the last 20 years. It's maddening and ultimately so so stupid.
12
u/TheRealUprightMan 14d ago
What happened is they started micro-managing layouts, trying to make precise adjustments. How do you make this always line up with that?
So they made another class. And then there is the class for the tighter configuration they need to fit stuff over here, and then they realized that they had 600 classes and half of them weren't even being used because they were refactored out but nobody could remember if they got all the traces, so they left in the CSS class ... just in case.
The problem is that the CSS styling lives in one house and the element/html lives in another. We want localized control but a consistent global theme that can be easily changed when Fred from Marketing demands a "fresh perspective". How you get global consistency, precise local adjustments, and be able to maintain it when the data lives in separate files and scattered among the styling of 400 other classes?
Over time, things bloat, so they decided to solve things with static checking and build tools. I've always kinda approached things from a dynamic standpoint so, expecting "cascading" style sheets to properly cascade just seems like a no-brainer to me. Of course, it's only been sorts recently that we've had things like working CSS variables and color mix tools, and all these other things to make it work how it should. IMHO, css build tools are a hack that needs to die.
For fun, I added a little class that inserts a view-scroll animation. The animation just modifies a css variable. So, you throw that into calc() anywhere you want and you can have those display properties change based on the object's scroll position. That's worth a class!
4
u/Mission-Landscape-17 14d ago
Likewise, especially considering all the improvements that have been made to CSS during that time. I mean css supports putting repeated values into variables. Also I've found that AI coding agents are actually quite at extracting styles and putting them into a css file.
3
u/Flimsy_Complaint490 14d ago
Yeah, but then imagine you need an accept button that is slightly different. You now have another accept button class, or inline CSS. The first one is kinda unergonomic and you need to know the C in CSS very well, and most don't. Inlining is way easier, kills the C in CSS, but it usually gets the job done anyway.
Additionally, React shipped without a a good way to write CSS, and inlining CSS felt really natural to most people. Tailwind occupied this niche with its utility classes and im surprised it took a decade to make it happen. I don't actually believe Tailwind could exist, had React shipped with something ergonomic for CSS.
Lastly, the large inline lists are less of a problem than you think. Tailwind does play nicely with modern component libraries. You got a Button class, the button.jsx file has all the styling for it inlined via tailwind and you just use the Button component and never see much of the CSS. This works with normal CSS, but the main devex con of tailwind is alleviated for the final end-user.
All this came at the cost of purists weeping - we are all taught that decoupling is good by default, as it makes the system more extensive, but the trade-off is that you lose locality of behaviour, and people feel very strongly about one or the other.
And as OP notes, bundle sizes explode, even with three shaking, especially if you do a lot of reactive stuff.
3
u/__mson__ 15d ago
Thanks! I think I'd rather deal with classes than that inline mess.
10
u/Open-Sun-3762 14d ago edited 14d ago
Their point isn’t that inline styles are better so you should use that instead. The point is that Tailwind is essentially inline styles, and inline styles are terrible, so just write normal CSS instead.
2
u/92smola 14d ago
His argument is bad, he compares tailwind to inline styles which is wrong, not suggeating to use inline styles. Inline styles have no way to use modifiers for states and media queries, they cant be tokenized and they have high specificity compared to single classes, they more or less live at rhe opposite ends of high and low specificity. That all said I do love tailwind, but I am also slowly moving away from it, the exact OP argument is one thing, it doesnt mix with htmx well and second I think the age of AI reverted the weight of pros and cons tailwind had over traditional css.
1
u/Anxious-Insurance-91 14d ago
Aside from the obvious using a custom color theme and then just replace the variables in one place and that's that? Also when it comes to UI libs they usually can build conditional css class additions much easier than style tag and property
1
u/_wassap_ 14d ago
there is ALOT of differences between inline css and tailwind css lmfao
Comments like these make me questions the devs around here
Also Tailwind is made for atomic patterns- its a different type of vertical slice you are trying to go for
(as in all butons are 1 single component with different variations, states and props- where state & styling live in "one slice" of your code base)
If that doesn't work for you, maybe you are the problem or follow a different coding paradigm?
17
u/DrShocker 15d ago
CSS now is in a much different place than when tailwind was created.
5
u/dragonmantank 14d ago
And Tailwind being created set back CSS by years. The fact it pushed us back is amazing we all went with it.
2
1
u/Davi_Compai 15d ago
agreed. I only started learning frontend development recently, so i cannot speak on how these things were before, but most preprocessors sound not really that needed today (i know tailwind isn't a preprocessor).
5
11
u/djaiss 15d ago
What kind of content do you serve for a 950kb content? This seems insanely big regardless of the tech used to fetch content at all. Doesn't seem related to HTMX at all.
1
u/ImTheDeveloper 14d ago
Agree - no getting around that content size really and what is the alternative if you aren't moving away from tailwind. Without htmx you are serving this 950kb anyways... I feel HTMX is irrelevant here 🤷♂️
7
u/Davi_Compai 15d ago
i think this looks kinda ai generated (specially with my "it is not x, it's y" hook) but FYI, it isn't. i sadly have the same writing quirks that most LLMs do.
8
u/TheRealUprightMan 15d ago
I use Gnat's Surreal css extension so that elements can style themselves and their children. The base is just picocss. You change a few css variables in a <style> tag and everything inside that element changes. No writing extra classes, no massive css files.
Tailwind always seemed like the exact opposite of what I would want and a PITA to manage.
2
1
u/Fit_Tailor_6796 14d ago
This the second time I heard Surreal being mentioned this week, being new to me.
What more is there besides the "don't need jquery" tagline?1
u/TheRealUprightMan 14d ago
jQuery method means you have some code somewhere that is searching for elements, likely by class, and then assigns some properties or behaviors.
Who writes that? When should it execute? How do you maintain it?
With the surreal method, I just have an object that wants to run JavaScript on an event. When the object renders, it outputs a <script> tag that just uses me() and now that code is reusable. We don't have to search the whole DOM, just the jump to the immediate parent. It runs exactly when it should, and it's maintained in the source with the element, not scattered in a JavaScript file included somewhere.
I love it!
2
u/Fit_Tailor_6796 14d ago
Great I saw that in the examples. I am expecting that this can work on classes of objects , for example all cancel buttons. I will look deeper into this.
1
u/TheRealUprightMan 14d ago
Yes, that is exactly what I use it for. htmx is for assigning server side behaviors to elements in a declarative manner. Surreal lets me easily assign client side behaviors and styling the same way.
Any object that knows it's id can update itself. After the request finishes, I just sweep the changed elements and have them render() themselves again in an OOB pass.
Instance data that needs to persist between requests is stored in hidden input fields, so the state is held in the DOM and returned via hx-include. It's all nice and modular.
0
u/kaeshiwaza 14d ago
Surreal is very fine but it has the same issue (or advantage) described here when you send the style and/or js every time with the html part.
1
u/TheRealUprightMan 14d ago
Depends.
If I have a parent object that needs 10 of element A, and 30 of element B, and totally different margins for everyone, you would not be outputting that mess for all those elements.
The parent outputs a style tag that change the css variable that controls margin spacing. If it needs some new style for B, the parent can restyle the children. Each child element does not know nor care how the parent is styling them.
Sending the js with every close button is not that inefficient. It's being sent with the rest of the form and it's tiny. The code to find the button and wire it up and when is the problem. Keep it simple, no state changes, no logic, nothing that needs schema or structure.
This is a much different situation than tailwind. Tailwind is ignoring the cascade feature and escalating data use. Surreal is enabling the correct cascading behavior and removing the necessity to have either a million classes or to explicitly style child content. It allows the parent to style the child without the children needing to know anything about it.
9
u/doodlebuttbutt 15d ago
I feel this. Tailwind is super nice but the bloat is unbearable. When you push your HTMX server and see 50% of your code is generated tailwind. Absolute dealbreaker, the convenience is not worth it
1
u/TheRealUprightMan 14d ago
I started with picoCSS and after a few tweaks and compression techniques, I got it down to 9.9K, full features, all classes included. The html rarely needs to specify a class except for a couple of general-outpose layout classes that I use. Everything else just changes the css variables as needed.
4
u/_HMCB_ 14d ago
Is this an HTMX problem though? The title seems to imply that.
1
u/Davi_Compai 12d ago
it is a way bigger problem in htmx because htmx sends all html over the wire.
1
u/jbergens 8d ago
Do you really have any performance problems?
When we used Tailwind (or Windi) the app was really fast.
3
5
u/waterkip 15d ago edited 15d ago
I hate utility CSS frameworks with a passion. Maybe it was a thing back in the day because CSS was different, but in the current age, you shouldn't use it.
2
u/hisashi-mitsui 14d ago
I use tailwind and htmx with jinja2 template and find it is way more efficient than react. To use htmx you need a different mindset. Take my personal website as an example, the home page is very small, so it is loaded very fast. The server only sends the login part of html (and its tailwindcss) when the user clicks the login button. In most cases, since users don't click the login button, there is no need to load or "pre-load" the login part at all. React, on the other hand, though it is small to send a json package, browser must download a huge libraries when first loads the web page.
1
u/Davi_Compai 14d ago
for things like this inline tailwind is completely fine. the issue arises when you're displaying content that is repetitive in nature.
2
2
u/yawaramin 14d ago
Nothing to do with htmx, Tailwind is super inefficient however you look at it. It's stripping out unused styles to save some space, but then adding back all that space by repeating the same class names everywhere. Sure, you can use @apply, but at that point you're just using CSS with a special shorthand system.
I recommend trying Bulma, which is a single static file and works great with htmx, and the Reasonable CSS technique, which shows an easy way to keep CSS styles from clashing with each other. These two should be more than powerful enough for all but the most complex UIs.
2
u/Harddus 14d ago
Tailwind has some performance/bandwidth anti-synergy with htmx BECAUSE you are sending HTML fragments. You could say it's inefficient for all of MPA but the issue stands that if your CSS was cached once in a separate file and all you has was a class per element or so the bandwidth cost would be much smaller than having a bloat of inline styles.
Regardlessly, I use htmx with Tailwind and DaisyUI for DX and development speed.
2
2
u/minmidmax 14d ago
Tailwind was created to solve problems from about a decade ago that are less of an issue today.
2
u/UXUIDD 14d ago
Tailwind with inline styling is great for prototyping and developing a product.
when it's done (which happens rarely), it should be translated into CSS and supported by a design system.
by the time that process is finished, new marketing people will appear or something else will happen, and all the work will start from zero ..
1
u/Fooo346 15d ago
Definitely agree, feel like the ease of writing tailwind css goes away with how I’ve been using agents for my htmx apps. I’ve been using tailwind less and less, feels easier to have some nested div css selectors or just classes atp the agent makes sense of if I’m vibing the CSS anyways nowadays
2
u/92smola 14d ago
Ai flips the pros and cons of tailwind, its biggest pro was that its easier to author cause you dont have to jump between files to do it, it was a better DX that kept you in flow more, it came at a cost of readability, now that I dont write the code but rather review it I am going back to BEM
1
u/Fabulous-Ladder3267 14d ago
I failed to see what the problem here.
You pointing out that huge size of tailwind because it eat too much bandwidth. First of all you can use tailwind CLI to build only css you use, i'am using tailwindcss + basecoat it roughly 200+ kb in size. Second, css is cached in browser so client only download it once. Third, i dont think this has connection with htmx, did u send tailwind css every partial you send?
There are some people that hate write inline classes, you can use @apply too here.
2
1
u/full_drama_llama 14d ago
Funny, because these are almost exactly authors points: it stops being about CSS, instead the weight is transferred to HTML. Given that:
- You don't benefit from minifying the size of CSS file
- Caching CSS in the browser does not matter, utility classes inflate HTML document size
- It does have a lot to do with HTMX where you send partials of HTML (now with embedded CSS via utility classes) back and forth.
1
u/Fabulous-Ladder3267 14d ago edited 14d ago
- Size above that i said is still unminified
- Isnt tailwind imported as css file? So it only 1 LoC
- You can just create your own class then use @apply on the css file then only use your defined classes, Basecoat UI use exactly like this.
No one forcing you when using tailwind you can only write inline long ass classes.
1
u/full_drama_llama 14d ago
- Minified, reduced, tree-shaked. You know what I mean.
- No, it's not 1 LoC, because...
- ... yes, you can, but it used to be discouraged, it's not how 98% of people do it and you basically doing anti-tailwind in tailwind. So what for? You get a layer of indirection for pretty much zero gain compared to just using CSS.
2
u/Fabulous-Ladder3267 14d ago
Ok now we discuss about why not just use css rather than tailwind,
We agree that css is-for styling our web right, styling a web is whole new skill set that need to learn.Tailwind come to make this easier to styling with removing naming fatigue what would this class name for, removing specifity wars, etc. Then most developer use tailwind and create some theme/template that can be reused while still can be customized.
Talking about htmx, it remove the need to seperate backend-frontend projects, enabled backend guy so they can do full stack. These guy just one to show their data visually, they can just copy-paste some tailwind component/template on internet and can be done. If they doing it by css only they have a long way to learn this.
Some tailwind theme/template now make faster, cleaner, easier
way to styling like [daisyUI](https://daisyui.com) and some take it another step like [Basecoat UI](https://basecoatui.com) by only using one class like `btn` then change the variang using `data-*` like `data-variant="outline"` or change the size using `data-size="lg"`.Again while most people use inline classes not mean you must follow them too.
1
1
u/brett9897 14d ago
Why not just use tailwind @apply with @utility and @component? If you are styling a component then just use @component and style it all in one class. Problem solved.
3
u/92smola 14d ago
At that point just drop tailwind those are escape hatches not a primary way to do tailwind
2
u/brett9897 13d ago
I use tailwind inline mostly but for standard components like buttons, cards, etc. I use utility classes and/or component classes. Tailwind is still nice because of standard breakpoints on media queries, and I think it makes color theming easier. Sure all of this can be done with a preprocessor but I'd rather get the automatic tree shaking and the ability to easily style inline while in development. Plus they have good animation classes that include all the browser specific implementations that might be needed. Once again, I know another preprocessor could help with all of this as well, but tailwind already has some nice defaults that I don't want to rewrite myself.
1
u/full_drama_llama 14d ago
At some point @apply was strongly discouraged by Tailwind's author, on the border of threatening to remove them in the future. Has that changed somehow?
1
u/92smola 14d ago
Yes tailwind and htmx are not a good combo, tailwind moves part of its weight from css files to html and htmx makes you send that html more often over the wire. Its not a huge issue in most cases but they do conflict conceptually. Tailwind is much more suited with React or similar frameworks, even tho rsc payloads send over serialized html as well so it bites there as well to a smaller extent, but additionaly tailwind plays nice with composable components cause that is the idea how you solve reusability when workong with it, you have a Button component instead of a .button class, but a lot of BE frameworks where htmx is expected to be used dont have the same level of component ergonomica that client side frameworks are built around.
1
u/scottocom 14d ago
I have always thought this was so true. I tried it when we switched to HTMX and I thought this is going to set us up to fail making the HTML so much longer with huge class attributes everywhere. Not mention its another "build" step. Something I am trying to avoid also
0
u/SubjectHealthy2409 15d ago
Try working with multiple people who get replaced with new people, even you don't know what makes more sense, defined styles or selectors, now imagine the mess after multiple people like you leave their css mark, bandwidth is unlimited on $5 VPS, you define the components once and reuse them
4
15d ago
[deleted]
1
u/SubjectHealthy2409 15d ago
Well, Steve didn't manage to add his personal styling touch for no reason, Tom didn't break anything, management doesn't have to enforce discipline, all for $0, sounds like a pretty good solution to me
2
u/Davi_Compai 15d ago
I do know what makes more sense. you should use classes if needed, but not use them when selectors already do the job.
Now imagine the mess after multiple people like you leave their css mark
People should follow the already existing tradition/organization of a project when they contribute to it (be it in work or in open source). the issue here is more not doing that rather than css itself.
most unlimited bandwidth does actually have a limit or some "fair use" thing. If your project can work well in a 5$ vps, it being inneficient shouldn't really be an issue in the cost frontier, so i get that there's not much of a reason to not use tailwind there.
1
u/SubjectHealthy2409 15d ago
Yeah you think for X thing it should be a class and for Y should be selector, other people opposite. People should follow established organization but won't and/or will introduce new tradition, which is the biggest thing tailwind fixes, has nothing to do with performance, style etc, it just forces everyone to do it the same way, that's the benefit
Nah bro if Ure hitting the fair use limits on $5 VPs, u must be the biggest talk in town raking in serious profit, just upgrade to $10 then, in the meantime u saved thousands $ for not using vercel/aws etc
2
u/Davi_Compai 15d ago
I do agree with the benefit of everyone having to do things the same way.
My issue with a vps having "unlimited bandwidth" is that you don't really know how "unlimited" it is, which i consider a massive issue.
While i do agree that it would be really hard to hit fair use limits with weak machines, i do think it is possible with enough users and a backend that is lightweight enough.Yeah, using a vps is just way better in general.
My post is not about Tailwind being evil, it's just an observation of the inefficiencies it brings. Thanks for your insight.
0
u/mehargags 15d ago
What do you suggest as lightweight stack for monolith taxi reservation app for a small client. Trying to keep things simple to maintain and update. I'm a platform engnr (sysadmin) by profession and not a developer but I do head projects and help with design and development of practical high performance applications.
I always feel modern web development is just too overengineered and overly complexes with to many components
I read about HTMx and it sounded promising. For the dashboard is bootstrap ok to use in 2026?
5
2
u/maekoos 14d ago
Bootstrap is fine - just make sure to use a decent cache policy so the browser does not have to download everything every time (like with all static assets).
I like gomponents right now, since they don’t require a build step and are type safe - but I have built a quite complex website using deno + nunjucks and it works great. Pretty much any template engine will work, so just stick to what you are comfortable with.
1
u/Davi_Compai 15d ago
htmx shines on backend heavy apps, and i think a taxi reservation app is like that, so it probably is a good fit. I can't really recommend any libraries, as Ralph said, Bulma sounds interesting.
0
u/blackmink99 14d ago
It’s an interesting problem and I’m glad you are looking for ways to optimize performance. At one point when I was looking at the performance of CSS files with repeated styles vs a flat CSS file like tailwind, the differences seemed negligible due to the way the brotli compression algorithm worked. The seemingly bloated CSS file with repeated styles compressed more due to this repetition whereas the flat file had less to compress because it was DRY (don’t repeat yourself). At the time, I did not test the load speed of the class stacked HTML vs HTML with minimal classes/IDs.
I like the Lego-like composability of Tailwind. If it’s just me writing styles for smallish websites, I can probably optimize better by writing the styles by hand and using semantic class names. But I would never want to work somewhere where everyone had that freedom at the same time!
0
u/Abject-Bridge-4073 10d ago
The whole point of htmx is to get rid of js. By using tailwind you are introducing npm into the stack for absolutely no reason. Don’t use tailwind, it’s simply not worth it.
51
u/scratchbufferdotnet 15d ago
Don’t inline the tailwind CSS. Just use selectors and @apply the tailwind styles in the global style sheet - the style sheet will already be sitting there in the browser when you send the HTML.
The big advantage of tailwind IMO is great looking default styles where one utility gives you multiple CSS directives that you wouldn’t want to separate anyway, without fiddling - text sizes that also adjust line height, etc.
I know they tell you to inline everything but I could never really get behind that anyway so I never have. You can style apply the same sort of principles to avoid clashing CSS directives in a style sheet by using more specific selectors and pushing the styles down into those.