An SPA Alternative
htmx.org
htmx.org
From the user point of view, I think there are two main types of experiences on the Web:
a ) Interactive documents. Basically web 1.0 but today we want fancier transitions and interactions. This can be provided by htmx and should always have been developed declaratively. It should ideally be provided by the browser and htmx shouldn't need to exist. Examples of this are Gmail and most social networks and forums including this one.
b) Desktop apps-but-I-don't-want-to-have-to-install-them. This would be things like Google Docs, Photopea and most real-time games. To deliver this, right now we have a browser that has become almost an OS inside an OS, to the point only Google can keep up with the complexity. On top of that, we pretend apps are documents and for all the imperative code we need we use a scripting language that was not meant for that, and we need a really complex VM just to keep it more or less performant. For this use case I think at some point we should move all the way into just delivering apps, if not native apps, something like wasm, where the browser tab would just be a vm player.
Rich Harris speaks towards that here: https://www.youtube.com/watch?v=860d8usGC0o
E-commerce stores have different interactivity needs than blogs, which have different needs than documentation, which has different needs than dashboards, which have different needs than real-time collaboration tools, and on and on and on.
Much of the framework angst is around the assumption of a singular tool for all these varieties of interaction and the annoyance that comes with not acknowledging the trade-offs.
Plus the web itself is changing, so the breadth of this spectrum is increasing. Years ago, the ends might not have been very far apart but they are diverging more with each new use-case and app idea.
But to me, writing my markup in JSX (really, TSX with TypeScript) and using scoped CSS solutions was too good to pass up. I just couldn't bear writing text-based templates.
That's why I built Reactivated: combining the best of both worlds. Server-rendered, simple markup — albeit still in TypeScript — but you can add interactivity as needed.
Of course, HTMX is far less opinionated and framework-agnostic. So it can be used with any number of libraries / stacks.
[1] https://www.reactivated.io
[2] https://www.reactivated.io/documentation/philosophy-goals/#t...
[3] https://www.reactivated.io/documentation/philosophy-goals/#r...
[4] https://htmx.org/essays/how-did-rest-come-to-mean-the-opposi...
I know my alternative approach, htmx-enhanced hypermedia, isn't right for every application, but it can be a much simpler approach for many applications, and, since it is so simple, can be used to conserve complexity in applications that have parts that are not amenable to the hypermedia approach.
I share your sentiments about SPAs, and I've been trying to get back to a simpler web stack.
One of the hurdles I keep running into with libraries like htmx and Alpine is that they don't play nicely with Content Security Policy. And I'm reluctant to forfeit CSP to use a JS library since CSP is the most robust solution I've found for preventing XSS.
Alpine is working on a CSP-compatible build, but it hasn't been released[0] and doesn't seem to be a priority.
htmx is compatible with CSP, but it effectively reverses the protection it offers. The attacker can inject JS through htmx directives.[1] I know there's hx-disable, but this degrades CSP's effect from "secure by default" to "secure when the developer remembers to mark the subtree as containing user-controlled data."
Is there a way to use htmx without forfeiting the benefits of CSP?
[0] https://github.com/alpinejs/alpine/issues/237#issuecomment-9...
which, I think should be the case: I don't think htmx should have to exist, I think this is just how HTML should work. That could address a lot of accessibility and progressive enhancment issues as well.
Sounds similar to the battles between es-queue-el and sequel for SQL.
https://abbreviations.yourdictionary.com/reference/abbreviat...
https://www.merriam-webster.com/words-at-play/whats-an-acron...
I also pronounce it S P A, so "an" seemed immediately correct to me.
Make sure to check other essays at https://htmx.org/talk/ (scroll down for Essays)
Occasionally you get a head nod in the direction that “sometimes, React is the best tool” but most of the time it’s Simpsons memes stoking a culture war.
If you’ve worked in an org where someone with decision making power has drunk the “progressive enhancement not SPA” koolaid, then it’s just as bad as someone who has drunken the SPA always koolaid - at least you’ll find it easy to hire and find support/libraries with the latter.
Not just programming or math, in physiology you have entire research groups worked up about a molecule that causes dementia and after decades of research realise that the story was a lot more complicated than that.
You can almost recognise a healthy mind by the lack of such dogma, just don't make it a rule that would defeat its purpose.
The real sweet spot is it allows you to push server side frameworks like Django even further. You may find you can skip the SPA all together. And nothing beats the speed of development of a Django/Rails/Laravel.
Htmx is part of my go to stack for solo/side projects and my preferred stack on the job for crud heavy line of business applications.
Why would you need JS at all for a date picker?!
A couple of things I had to handle in the last couple of weeks: - Handling different separators for input - having a clear button to indicate "no date" - display the date in a different format
In the system I've used a mix of regular django templates, some Django unicorn, some HTMX, and some HTMX+Alpinejs
I pick the tool based on the the amount of interactivity I need on the page.
It's.... interesting. If you start out knowing you will do HTMX, then I found everything is much easier. Splitting off small small views to return just the right html after a hx-post is more labor intenstive than i would like, bit overall it's nice.
The hardest part I found was being able to have a fine level of control around the user experience, and solving that required adding a lot of javascript, which made me wonder if it was worth the effort and should have instead just used Vue to handle it.
I've ended up using a lot of HX-Refresh in responses (causes a page refresh) because it was easier to do that than to ensure all the different parts of the page updated at the right time.
The way it cascades htmx values down the tree is really handy, and lends itself to consise attributes on the html.
Overall I'd give it a silver-coated bullet rating. Certainly not a solid silver bullet. :)
This was almost exactly my first impression of HTMX as well. It's a huge step forward! However, for my tastes it demands too many tiny views and micromanaging, which somewhat felt like a drag on my productivity. For an alternative, take a look at Unpoly [1] which has more batteries included (i.e. create layers of interactivity that update lower layers automatically) and is centered around full page requests/diffs and less focused on injecting small page fragments everywhere. For my small apps, I could do everything in one view that took three or more views with HTMX. I can only imagine the views exploding for a modestly complex site. The biggest penalty for Unpoly is that it is quite a bit (~2X) slower than HTMX, which needs to be kept in mind and managed for larger pages with a lot of interactivity. I suspect this is because Unpoly loads the entire page and does a DOM diff to see what it needs to update, as opposed to injecting just a page fragment. In my tests, I was able to manage around this issue using layers. The big upside to Unpoly is that the full page refresh architecture aligns very neatly with Django's request/response cycle, which gives you pretty seamless interactivity and form validation. It also has a lot of batteries included that HTMX lacks. I think HTMX is terrific and revolutionary, but Unpoly fits my brain better while doing Django development.
I'm using it for a new frontend right now. Combined with a thoughtful CSS design like CUBE[1] that utilizes components but also leverages utilities to reduce CSS bloat I am writing mostly Ruby and HTML and very little JS and CSS and it feels great.
It's kind of back to the basics which means that I also do not worry about being on some framework's upgrade & dependency train or the mental health of future application developers/maintainers.
[1]: https://piccalil.li/blog/i-used-tailwind-for-the-u-in-cube-c...
I found out putting the ids for the htmx snippets in a typed datastructure (in my case Python with type annotations, since I use django in the backend) to be easier to find the corresponding templates, see all usages, etc. I think otherwise it gets a bit confusing.
http://youtube.github.io/spfjs/
SPF was a bit more focused on being easy to merge into an existing server side app.
I am glad to see this and hope it has some legs. It could help free us from the need to write every UI in JavaScript(ish).
htmx is more light weight, and very actively maintained.
React & Angular do scale this far, I have yet to encounter any who works with Vue that ships over a million lines of deployed code though I'd love to hear from you!
htmx would probably work great for something like GMail, but would be a bad choice for something like Google Sheets. Both are big apps, but one is more amenable to coarse grain HTTP requests because the UI isn't as interdependent.
Interestingly, I have seen a new app that provides a sheet with HTMX: https://www.licenseprompt.com/ (gif: https://twitter.com/WimpieNortje/status/1520419150245638144)
You're saying "I have all this code, what do I do with all this code." The answer is: don't write it!
I never done it with Vue (largest Vue app I ever worked on had roughly 200K lines of deployed code, all in, for the application, very thick client type stuff), but maybe with Vue 3 and the composition API this isn't an issue (I don't think Vue 2 would ever scale well developer experience wise this way)
I'm not throwing shade on HTMX, but there tends to be this energy around it that would make someone who, perhaps trying to weigh some options, stumbles across HN, sees threads like this and thinks oh gee! This sounds great without knowing exactly what that means. And it is true, that perhaps, that person is building app that needs scalable reactivity and fine-grained control, or something along those lines. I at least want to give a fair take on purpose for people thinking about it.
HTMX is great for its target audience, much superior to jQuery in this day and age, but you have to understand what its for.
(And don't start with "it's faster/more efficient", that comparison isn't terribly valid because the inefficiencies seen with React/Vue are largely an artifact of bad code/practices, not the libraries themselves.)
> All 3 require some form of JavaScript library coupled with markup to build interfaces.
With HTMX you're typically including one static javascript file that you just download, you're not using any kind of javascript build system at all. Where it has very limited scope it's possible to imagine a browser that doesn't have javascript but that has HTMX built in.
Calling it a javascript library might be a bit much, I mean you're not typically installing this with node/npm, or minifying it, or importing it. You're just including it in a script tag at the bottom of your site. While they both do technically run on javascript I think they have more differences than things they have in common, and saying "Well they're both just javascript libraries" is a very sophomoric take. I mean you might as well just say that all javascript libraries are the same, and it doesn't matter what you use. So why choose react/vue over jquery?
> inefficiencies seen with React/Vue are largely an artifact of bad code/practices, not the libraries themselves.
Ehh, I'm sure you can make a fast bug-free website in server-side assembly if you're so inclined but it's probably not the right tool for the job. The question is what kind of design patterns do the libraries/tools encourage, not "can I do X with Y".
- [1] https://vuejs.org/guide/quick-start.html#without-build-tools
- [2] https://blog.jim-nielsen.com/2020/react-without-build-tools/
It kind of returns to the original intention of the web.
Edit: wording
However, 99% of javascript blobs of hatred end up slower than downloading the pre-rendered content.
Also, by eliminating application javascript, it allows you to spend more time in your preferred language on the back end.
The downside is the same as regular HTML, although less pronounced: since you are driving application state through hypermedia (HATEOAS), the less coarse-grained your state or UI gets the more annoying things are going to be. There are some patterns that help but eventually, if you want to update 12 different places in your UI at once on every keystroke, the hypermedia approach just isn't going to cut it.
But these days (using transpilers and/or WebAssembly) you can choose just about any language on the front-end ...
On the other hand, the simplicity of the hypermedia approach, and the flexibility of ReST are still there.
We'll see.
Imagine not having html at all. You'd have to create pages from scratch imperatively by doing things like let element = createElement("p"); element.setContent("my paragraph"); parent.addChild(element); It'd be really ugly, a PITA to change stuff and error-prone. htmx is the opposite of that. It tries to make web development declarative again, among other things.
Instead of api models and client models, you just have models.
Instead of api routes and client routes, you just have routes.
Instead of unit testing api and client, you test one project.
Instead of having the client making N requests to load all the data it needs from the server (and being careful not to return more data than you need for performance reasons), you return an html with all the data it needs in a single request, and nothing more.
In the case of client stacks using SSR (like Next/Nuxt):
Instead of running the SPA on the server so the server returns the html rendered, you just make the server return the html rendered.
The benefit to the developer is higher productivity. The benefit to the end user should follow from that.
Even if you really needed it to be an API, you can always make the server side return either html or json depending on some request header. There's also a chance that the mobile version will be different enough from the desktop that it warrants new, custom built endpoints anyway.
[Tetra](https://www.tetraframework.com/) might be an alternative if you’re hell-bent on not using React.
But, if you want to ship quick, have a maintainable codebase in a technology a lot of devs are familiar with and have the power to instantly ship for mobile (and buy yourself some time to build one in React Native; code is going to be similar to React.js), I’d recommend using React.
You can use Capacitor.js for instantly shipping a mobile app with your codebase that “just works”. Use Capgo for affordable codepush and you’re set!
HTMX all the way if you’re not building an app cause not everything is an “app”.
At the same time, if you’re building an app with a framework unlike Phoenix, I don’t see why one would not go ahead and use a decent JS framework. Using frontend framework seems to be facing a lot of aversion and I don’t understand if it’s because of the inability to learn these frameworks or what.
Point is, your users just need a snappy app that works. That’s it! And using a robust frontend framework makes it easier.
Why should only <a> and <form> be able to make HTTP requests?
Why should only click & submit events trigger them?
Why should only GET & POST methods be available?
Why should you only be able to replace the entire screen?
By removing these arbitrary constraints, htmx completes HTML as a hypertext
I think the first three items are minor issues, at best, which in no way justify yet another DSL.The fourth is a reasonable point -- it's quite common that you only want to update a portion of a page.
But it's very unclear that HTTP requests are the way to do it.
For one thing, using HTTP requests as the transport for app event handling adds nothing conceptually. It seems nice to use something that people are widely familiar with to build an event model on top of, but HTTP isn't a good fit for everything. So you either need something else (javascript or another language/api/framework) or you awkwardly fit everything into this model anyway.
But more importantly, it implies a strongly hierarchical structure to your app UI, which I think is overly rigid and unrealistic. Content tends to be largely hierarchical, but frequently important cross-cutting concerns pop up... maybe not on day one, but maybe on day 100 or 1000. Now you're swimming upstream.
Also, it's not like there aren't a very high number of HTML-centric options available. It has an interesting low-level approach, but in the end we're developing apps and UIs. It's very unclear to me whether htmx really offers advantages that other approaches don't meet or exceed.
You say what is the advantage before :) :
> ... maybe not on day one, but maybe on day 100 or 1000.
That is the thing. Is Wonderfull when you actually wait and see if you truly need the extra complexity of things.
Go nuts when is time to go nuts.
But is nuts to do it now.
Instead of HTML, CSS, JS in that order maybe they got chucked right into a NextJS / Tailwind twitter clone course as their intro to web dev.
Say I have my css sheet included, now I still need to set the class and id attributes everywhere I need styling.
Are you telling me the client needs to parse the html result and add those manually? Seems absurd. Are you telling me a real Hypermedia API would return stuff like
<div class="...">data</div>
? That would seem equally absurd, why would the API concern itself with css classes lol.
That's what I don't get
Take an old school original rails app. No JS. Nothing. If something is gonna happen it is because you clicked a link or submitted a form.
In that app any page is generated by the server and must have any classes defined for css also rendered.
So the server is already needing to know about this and inject those classes.
With HTMX it is the same thing except you render partials sometimes and sometimes the whole page.
Beyond that I don’t think adding an id or class here and there is too bad. I’d avoid class heavy frameworks, as I believe you are alluding to.
<html> <body> <div>Account number: 12345</div> <div>Balance: $100.00 USD</div> <div>Links: <a href="/accounts/12345/deposits">deposits</a> <a href="/accounts/12345/withdrawals">withdrawals</a> <a href="/accounts/12345/transfers">transfers</a> <a href="/accounts/12345/close-requests">close-requests</a> </div> <body> </html>
What I don't get is who says I want to have all of that html displayed in this exact form anywhere I make a request for account info? Say I want to only display the Account balance - are you telling me client has to cut and parse the html response for that? How much html parsing is that gonna be all over a web page?
Also the example I gave below about setting the css classes and ids inside the returned html elements...
This is my slight “ugh” against it and why I prefer the idea of the frameworks that just get the entire page and do a differential swap because architecturally that is simpler. No need to create lots of weird little partials and wire them up.
There's probably some kind of balance between giving every partial it's own URL and allowing each partial to support a filtered response. You could write a little middleware for your http server to support the filtered response on every endpoint that returns HTML.
This would process the app response and filters/zoom to the part of the doc you want. The app could be agnostic and it reduces the amount of crap sent over the wire.
That's probably safer in some ways than filtering server side.
https://htmx.org/attributes/hx-select/
I think it would really benefit the project to have more documentation/examples of architectural patterns for how an app might use HTMX.
there is a page here with links to various repos people have put together:
It provides a smooth UX by fetching next page's HTML in background, then replace the DOM by compareing the diff in HTML. So you won't see a blank page while navigating between pages.
Things I remember from the last time I had to deal with these libraries were redirects and hard-to-debug JavaScript issues due to so much JavaScript relying on document ready/onload events.
They turned Turbolinks and extended it into a complete framework. I really want to give it a try.
Great TTFB as I don't need to send it to node to render js, faster navigation for many users with slow plugins and easy to implement.
This seems to do the same thing, and much more. I really need to try htmx, looks cool!
What tires me is the groupthink around web development. SPAs and server rendered content aren't better than one another. It's annoying and unreasonable that the current trend is that SPAs are bad. They are not. Everything bad with SPAs I've seen is caused by developers not getting their priorities straight and by bandwagoning. Stop making webpages complicated and you'll find that many problems disappear.