With HTMX I'm finding myself needing to have as many backend views as I have ways of interacting with a page. I still have to write the frontend, and on top of that I gotta make a bunch of one-off backend views for many interactions. What am I doing wrong?
I haven't actually played around with HTMX, so I might be sizing it up wrong, but it's mission statement just never resonated with me enough to want to try it out.
It wasn't about writing less code (although it is about writing less javascript) but about working with the concept of hypermedia instead of against or around it.
I have the impression that older web frameworks did in fact have a good amount of statefulness built in, and that causes a whole host of issues, so I believe to understand _why_ modern backend frameworks really don't lean into that.
But neither is React. And we've been reaching for it by default for everything and that's been a mistake.
So much of what's built these days could be stateless MPAs. Servers have gotten crazy fast, and I'd certainly rather optimize for page size and server latency than build a React app.
With the upcoming views transitions api, a bit of htmx, and custom web components and you get 95% of what React offers without anywhere near the package size or complexity. You don't even need a compile step.
I'd never argue htmx is best for all use cases, I would hate for it to mutate the way React has, trying to be everything to everyone. But I hope htmx is the start of re-thinking how they approach the web and realizing that there are significantly simpler ways to build a frontend.
Unfortunately worked with someone I was reasonably sure was a ~~paid shill~~ part of some Vercel partner/influencer programme as they were adamant we must use Next (and Vercel but they lost that argument) for a project the team absolutely didn’t need to use it for.
In fact the rewrite of a project was worse than the original application. The original was snappy and instant and just worked meanwhile the Next version was slow, full page refreshes for every action, and just totally awful.
I couldn’t get off that team quick enough.
Next is ironically fast if you prerender/static generate AND the client disables JS!
The issue with many SPAs I saw was that state had to be managed BOTH in the browser AND on the server. This resulted in more code, longer time to market, and reduced velocity.
The SPA route can be a requirement (e.g. when a highly interactive UX is warranted), in that case there's no way around it. But when it's simply a bunch of forms in a business app, that's usually not the case: in those cases I'd go with a traditional "multi page app" and/or HTMX.
More likely than not you get designs that create all kinds of messy app states around and users then can’t properly use bookmarks or back button. This in turn leads to hotfixes and more mess in frontend. Forcing designers to think about urls and their names is in most cases very good.
Rather than limitation, I think of it as a constraint. The best engineering takes place under constraints, because when you're unconstrained you have a high chance of repeating mistakes that have known solutions. In this case, you rightly point out that the UX of the browser has certain limitations and making all state URL-addressable is the interface to that UX.
as I say in the post, HTMX is not for you if you are building a web app that needs this ... but in 90% of cases web sites don't
Hypermedia Systems is a great read, by the htmx creator, available here:
The main advantage people feel with htmx is that your routing is serverside and you dont have to keep quering/filtering/transforming data from your api to fit UI because you have access to everything. Do you suddenly need number of groups user is part of in this one only place? Well api doesnt have it so either extend api (figure out how to name it and where to put it) or you fetch all groups user is part of and count them on frontend. This middlelayer is something i realized i more often than not need. And when i need interactive UI i can initialize webcomponent or even have react island. Since htmx (and other similar tools) dont expect to overtake whole DOM but work with elements they can be very isolated if you want them to be.
I think HTMX appeals to fullstack devs like me who often find themselves needing bespoke API calls for their frontend views anyway.
When writing tightly coupled backend code for a frontend view, I'm quick to think "well why am I not doing this entire feature in the backend, anyway?" And HTMX makes that super easy without giving much up.
But the opposite reaction would be equally valid.
Yes.
> Which is convenient, but hardly "less code"
It is strictly less code because you're no longer validating on both client and server. It's also more than just "convenient", because it also forces you to stick to the well understood browser UX, ie. all state is URL-addressable.
Nothing wrong with JS, I'm just not fluent in it. Whereas, Python is my native programming language, and I can just see it without looking anything up. This is why I love HTMX. I just want basic web interaction without having to do it all in Javascript.
But yeah, if that doesn't really fit your mental model then I don't see a huge reason to give it a try.. other than it IS fun!
That being said, HTMX is not for everything. It’s great for internal tools as long as you don’t have very complex role-based access model. But security and access rights is where I think HTMX quickly becomes too complicated compared to a more traditional approach. As far as having “too many back end views” I do think that is down to you choosing an “incompatible” backend for your HTMX. It’s hard to say without knowing your details. You do say that you put a REST api behind it, but why would you do that with HTMX?
Certainly agree that HTMX is not for everything. Nor is Raku ;-)
Traditionally I first build it as a fully server-side rendered page. Once that’s working I setup my views to return HTML partials for different parts of the page.
So I might still have multiple views (or I might have single views that handle path parameters, query parameters, etc), but each is then basically just returning part of the existing template:
Full page: return render(request, "jobs/index.html", ...)
Some part of the page: return render(request, "jobs/index.html#status", ...)
You can sort of think of this the same as you would with JSON API endpoints, where you still need different endpoints handling different HTTP methods (GET, POST, etc) for the different CRUD operations, and there’s a tradeoff regarding how granular you get with views, but typically you can make the views pretty generic and reusable (the same way you can make JSON API endpoints that essentially just serialize database query results). There’s an article [0] that gives an example of a similar approach.
More recently I’ve been using a more component-based approach, using something like htpy [1] where I build up the page out of components (like you would in React), and sprinkle JS and CSS into the HTML with Alpine and Tailwind.
[0] https://www.circumeo.io/blog/entry/django-htmx-and-template-...
If you have problems filtering in the backend but it's easy in the frontend your backend technology is probably lacking.
The pattern I've been happiest with is when I can have a templating language designed to work really well with a component (or partials) approach.
I break down the UI into smaller components as I add more HTMX interactions. The UI is effectively a tree of nested components, much like react or svelte. When an HTMX request is sent, the API handler logic runs and instead of returning a success response it sends back HTML for the individual component(s) that HTMX needs to update.
tl;dr; When a request comes in, check headers to see if it was an HTMX request. If it wasn't, handle the API logic and return the full HTML page. If it was an HTMX request, still run the API logic but send back only the rendered components/partials that changed.
> send back only the rendered components/partials that changed.
What does this look like for you in practice? I’m imagining you have specific APIs per component/partial that mimic what happens during the full page load. Is there anything else you’re doing?
Also, does “changed” just mean the resource was requested and you return a potentially refreshed partial? Or are you returning a signal to ignore triggering a page update when you can identify the rendered component has no difference?
Maybe I need to be writing REST-looking form submission endpoints.... but then I have the immediate issue of presentation.
Doing things the "htmx way" on a team requires buy-in from more than just devs and that can be hard.
We should be careful not to push htmx too past what it was meant for, as well. I remember how much I admired React when it was released for its simplicity.
The amount of boilerplate I had to write just to keep DOM attributes and JS properties in sync was not fun, the impedance mismatch between them (DOM attributes being strings) was painful to deal with, and templates/slots felt much worse than the React way.
The DOM didn't seem like a great model for moderately complex apps. Feels like web components didn't take off for a reason. IMO they feel like the solution you come up with when you create an abstraction in paper instead of writing a real-world thing that will solve your immediate problems. Not very pragmatic.
Plus they only work with JS enabled, unlike React+SSR where you can progressively enhance your app.
Overall not a great experience for user-facing apps.
You can SSR web components using the Declarative Shadow DOM API, which is finally supported in all of the major browsers and works without JS.
There's lit.dev for an easier approach.
At that point why not just use React? What do I get from using Lit instead?
The design of web components could be better, but I much prefer them to the true nightmare that React development has become. And the api is stable, which means a longevity that frameworks don't have.
| no SSR nor progressive enhancement
I have not been impressed by React SSR in the wild in terms of progressive enhancement. This seems like more of marketing promise than a real world experience. Do you have any examples to link?
I recently rewrote a site that was built in NextJS into Go+Echo+Templ+HTMX+AlpineJS, keeping just the Google Maps and Facebook components (but only injected as necessary, rather than needing a whole App wrapped around them)
The result was about 50% of the size of code that is much easier to reason about and test, better performance, simpler and smaller (size and resource) deployment - essentially better in every way.
Plus I wanted an excuse to use htmx.
I am not sure if this is intended as humor, but JavaScript came before CSS.
In those days the three content columns vertically aligned to the same height cross-browser.
* https://www.w3.org/Style/CSS/msie/
* https://webdevelopmenthistory.com/1995-the-birth-of-javascri...
The distinction either way is trivial, because at that time nobody was using either CSS or JavaScript as they required proprietary APIs. There was no DOM specification at that time.
JavaScript was created by Brendan Eich in just 10 days in May 1995 while he was working at Netscape Communications Corporation
CSS (Cascading Style Sheets) was introduced later than JavaScript. The first CSS specification was published in December 1996 by Håkon Wium Lie and Bert Bos.
apologies
Well, sort of! I suppose that for certain definitions of eliminating Javascript, this Javascript framework eliminates the need for Javascript completely.
(I'm not quite sure if this is the author's sentiment), but the point shouldn't be to escape JS entirely, but make it into something that can be used in a repeated pattern that works in lockstep with your application, such that you are neither creating custom JS for each page (e.g. React), nor blindly manipulating the DOM (like JQuery).
The division of roles between CSS and HTML is an almost contradictory point - your styling and layout should be coupled if you are to impose any meaningful order in your design. If you are rejecting the "decoupling" of front-end and back-end that React gives you, then why would you expect to be able to do it between HTML and CSS?
(i) I am deliberately starting from a(n over-) simplified pov to see how far I can get with zero JS ... but as I read the comments above I realise that, for real applications, I will need to "sprinkle" some Alpine and Tailwind here and there. (I chose Cro for the user auth.)
(ii) Indeed HTML and CSS are in an intricate contradictory dance. In the purest sense I think that my sites should be composed of reusable parts that sit within context. These parts can be composed from roles and may selectively tweak them. The roles convey aspects of the design (colours, typography, containment, scale, size). The parts contain content (text, image, actions), identity and semantic intent. Role mixing in SASS is a small start in this direction.
[This is a very weak stab at a very thorny problem ... please let me know if there is any reading that you recommend.]
HTMX is a great tool to bring the UI implementation back into the realm of more capable & expressive languages. And to start with a new perspective.
My personal preference is Raku, but you may prefer OCAML, Rust, Go, Python, Haskell, Elixir, ROC, Zig ...
I also really liked an idea about class-less CSS frameworks, as I was frustrated with all the `<table class="table">` and so on. Then I've tried it for one project where I had to integrate Leaflet map on a page. And it's just not possible to do with class-less CSS frameworks.
Since then I write `<table class="table">` and have zero problems with that.
#map{
foo: initial
}
#map *{
foo: initial
}
For the styles that are a problem? That’s maybe 10 properties you need to remove?Another solution might be packing the map in a shadow element so that it doesn't get affected by the page CSS.
Use a CSS preprocessor to add a
:not(.nostyle)
To all rules, and then add the nostyle class to all elements you want to exclude.
The problem would be that you have to add the class to every single element (and all children) to exclude them, and there seems to be no good way of having selector:not(.class and all children of .class)
The Shadow DOM method is really interesting though, I’ve never used it anywhere but it looks like it’s perfect for this application.…and look, that’s an okay mistake to make — it takes time to learn this stuff — but when you also go out of the way to pine for “the halcyon early days of the web before Netscape dropped the JS-bomb” it makes it difficult to take you seriously. A list of links is, like, the most basic essence of a website; if you aren’t able to make that work without a JavaScript library, what are you even pining for?
I know that HTMX has a much larger userbase, its main dev is well known and beloved, and the landing page doesn't look web 1.0
With that said, unpoly appears to have a similar feature set and one feature that HTMX doesn't: The ability to create modals without loading a new page.
1: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_att...
2: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/di...
I'm using Django, and a big positive of using unpoly is that I can write views like a traditional Django application and have a reactive frontend.
It does mean however that heavy pages impact front-end reactivity. So if there's only one tiny element that needs to be updated on the front-end, that takes more time than if the backend would only have to return a template partial (htmx) or some JSON (alpine).
Also, the documentation is really a reference. You need it read it front to back a few times to understand unpoly's capabilities.
It's strange that there are so few tutorials about it, because it's been around for a while already, it really has its use and it is still under active development.
It has "actions" that bridge a need for some client-side interactivity, without resorting to write lots and lots of JS. I have some interactive stuff that don't touch server. Also it's pretty easy to add more actions when needed.
And if I need to do something really complex, I can just go and read its source code. Which is really hard to do with unpoly and its really complicated OOP style.
In react today I'd still probably reach for Tailwind. In any other scenario I'd only reach for it I wasn't comfortable with CSS.
edit: I'm trying to impress the fact that things change. looking at if this library "won" or not misses the point.
React “won” Wordpress “won”
Java applets did not
Those iPhone web apps that were around before the App Store should’ve, but didn’t.
Tailwind undecided
I'm confused, HTML under tailwind is not any less semantic than under any other CSS toolkit.
soul = spiritual part of a human)
so except if there's a really fitting html5 tags (like footer, h1 , main ), we will have `<x-card>` `<x-avatar><img ></x-avatar>` (In case we must have an additional ) so that it's easier to convey the semantic (especially when looking in the dom inspector)
for the css we've been using tailwind (and couldn't be happier), but for personnal projects I guess picocss would be a really nice fit with `<x-semantic>` tags
> I am a simple sole [sic]
`href=#` + JS library + config file + setting routes for each tab button doesn't feel simple
I completely completely disagree. This is all you need.
How would you do that with Figma, YouTube, etc?
I am never going back.
The endless thrashing on front end borders on psychosis. Something is clearly broken, and that thing is my feeble mind.
WASM is the best thing that ever happened to the web. When other major web frameworks adopt template engines that compile to WASM, we will see a shift in focus on JS heavy frameworks, and just people building things instead of fighting and trying to remember all the weird quirks of JavaScript.
Spa-style interactivity without a need for an API is great.
Optional shared state between clients and effortless push-to-client is… basically magic as far as I’m concerned.
I have seen Blazor and it looks good but I have an aversion to anything Microsoft.
I just recently decided to go back in time and wrote a web app using Flask, all rendered server side, with a minimum of JS and JSON endpoints for a bit of client-side interactivity (e.g. autocompleting an input field). Very fast, iterative work. No duplication of data classes, no weird caching issues…
Felt like a breath of fresh air, sadly. Have we witnessed a full turn of the wheel?
But let's be honest: the frontend dev rat race had the effect to make the base web technologies better. Better CSS (variables, nesting, effects, media support, etc), better JS (webcomponents), useful libs available as wasm and so on... all good things that can be used natively and allow us to make better MPAs.
HTMX solves this, and it's mostly automatic. You get some nice transitions.
> How do you pass state between two pages?
You don't. You submit some data to the server, it generates HTML dynamically, you replace HTML on the frontend or redirect all together, you're done. The state is on the server.
Yes. You might call this an application, lol. You will require this no matter what, unless you have a fully client-side application. Like photoshop or something.
How so ? Vanilla JS has never been easier and more powerful.
> How do you pass state between two pages?
Why is it even considered to be a problem ? This is basic stuff. All web frameworks since the 90s have had this concept of sessions where you can store data that will be available across pages.
Sessions are a kind of global state. I mean temporary state, like when filling out a form and moving from one page to the other, but without submitting the results until the end.
Functions, classes, modules... everything is available to organize code. The mess some programmers make can be unstructured, but that's the case with any paradigm and yes, we've seen that with "modern" JS frameworks too. Spaghetti mess, lasagna mess, components mess or whatever pasta mess.
> I mean temporary state
What is the problem here ? It's as temporary as you need it to be.
Because the tooling has been here for decades and it works damn fine. No need to trash the frontend with ever changing piles of dependency and build nonsense.
when? View code in the back-end always looks like crap and never able to achieve the interactivity the front-end can. People wrestling with it was the reason SPA was born. There was no dictator forcing people to move on from such "awesome" working "damn fine" pipelines to modern front-end for no reason.
That's probably the fault of the people writing it. People can also write crap looking code using frameworks too.
> and never able to achieve the interactivity the front-end can.
That's what small sprinkles of javascript is for. You don't need incredibly beautiful interactivity in every pixel.
For some reason, it sounds like someone being held against their will, which is exactly how I feel about it too
My favorite stack right now is Astro + SolidJS. Maybe it'll change next week. Who knows?
HTMX pretty much enforces a 'one user action, one HTTP request, one HTTP response' pattern, which is necessary for a usable UX for users who can't see the data centre from their office window.
Anyway, back then the HTML was simple (but it was tables and spacer GIFs ha ha!) and the CSS even simpler. Now it's just such a chaotic mess that people actually think Web Assembley is a good idea; as if somehow they've invented something new: the sandbox and the machine code. Like running a process at the OS level and making _that_ better, more secure, etc. wasn't the right path.
HTMLx is as close to the UI as I'll come. Everything else is an absolute headache to get into.