The Hypermedia-Driven Application (HDA) Architecture
htmx.org
htmx.org
I’m using this approach (other library, though, which is called twinspark.js) for year and a half.
From TFA, they use the example POST /search where a snippet of HTML is returned from the /search call and is injected into the page. What would the backend look like? Presumably you still want HTML templating and component-based design instead of regressing to hand building the response, but what frameworks/packages/utilities exist in that space that don't assume they are rendering a complete page?
In particular, "whole app" frameworks like NextJS or SvelteKit are automatically mapping URLs onto a root component that is automatically decorated with all the chrome needed to make it a complete page. Is the approach to just overload those root page components and take all the chrome away to get a partial document in the response?
htmx includes headers, `HX-Request` which will be true if the request is an htmx request, and `HX-Target` that will be the id of the target element, if any, that allow you to modify your response as needed on the server side. This is very common: you have a single URL that satisfies both the htmx and non-htmx request (e.g. /search) and in the htmx case, you don't render the surrounding layout, but in the "normal" case you do.
If a server side option isn't available or is inconvenient, you can instead use the client-side attribute `hx-select` to select a bit of the HTML from the response for inclusion in the DOM.
For example I have a form that's something like
form_partial.html: partial form template: <form hx-post="{{ request.path }}" hx-swap="outerHTML" hx-encoding='multipart/form-data' hx-target="this"> {% csrftoken %} ... some other form stuff from django </form>
form.html: A normal page that includes that form: {% extends core.html %} {% include partial_form.html %}
Then in the controller code I choose whether to render the entire page (form.html) or a partial page (partial_form.html) depending on the presence of the htmx headers.
So the full load might look something like:
1. Visit mysite/coolform 2. Server renders whole page 3. Browser submits form data 4. If the form is invalid, return only the partial form, swapping the forms html and if the form IS valid, return a redirect
Another cool thing (checkout hx-boost ) about htmx is that even if you return a whole page you can actually still avoid a full page reload and only swap out the body component. So even though you're returning a few extra bytes the site isn't re-executing the entire JavaScript bundle every time you navigate to a new page.
I wonder what other platforms are going on right now in this same category -- anyone have more examples?
And in general how much "mind share" (or really development-share) it's getting.
I'm not super familiar with this but what I can say is that many of these things were inspired by Phoenix LiveView, and as far as I know LiveView is still the one that works best.
Here's a list of LiveView-inspired projects (including StimulusReflex): https://github.com/dbohdan/liveviews
An example edge case where this fails completely is a canvas-based interactive game, where you (a) cannot "ask the server for html" in order to update your game UI and (b) going through the server for every UI update is unacceptable for performance.
That said, people are realizing that in a very large percentage of practical cases (i.e., CRUD apps), you do not need the high fidelity of javascript and you can skip a lot of the related complexity by using simplified stacks.
The big fail would be if you use htmx at first but over time you end up grafting a bunch of custom JS on top anyway, and your backend is a complicated Jinja mess, which is what made old school Rails/Django projects total messes and caused people turn to SPAs + JSON pumps. It probably takes some discipline to stick with pure htmx and push back on requests to graft random crap on top.
In the case you outline, a canvas-based application, a hypermedia driven application is not going to be a good choice. However, that being said, it may be a good choice for parts of your application (e.g. the settings page.)
Thankfully many SPA libraries are now embedable within an broader application, so you can use that approach when it fits best, and other, simpler approaches in other parts of your application.
A tool like this that rely on server rendering (or livewire, hotwire, etc) is a perfect replacement for when your user interaction will need to reach to the server anyway (to save data or fetch something, etc).
For example, you're not forced to go back to the server to display a modal. You can have it already rendered on beforehand and when clicking a given button just toggle its visibility.
Or if you want to mark a todo item as "done" you can just apply the "done" styles with alpine.js or similar and make an async call to the backend that will persist the state, etc.
Going full "SPA" just because this is less ideal than state based react, etc does not compensate the overhead of everything else involved in any web application (SEO support, translations, security, authentication, etc) which are incredibly complicated to get right with SPAs.
How do I dynamically generate a list of deletable items? In react would be something like (simplified obviously) `contacts.map(c => <button onClick={apiDelete(c.id)}/>`.
I dont understand how could I generate dynamic lists without hardcoding Ids... is that a case where I would need to use normal vanilla js ?
Very interesting developing tech philosophy. I was a bit in the js bubble for a while. Its refreshing to see such a simple and powerful idea/tech outside of it:)
For example: in "how to update content", they discuss path dependent updates. Those are how remix does all it's updates - they use nested routes, so it knows it only needs to update a part of the page (eg only update the content of the page, leaving the nav alone, since an update occured only in the content part of the page)
I think the htmx folks would have a lot of issues with remix but I think remix takes a lot of the best of both worlds. Remix focuses on using basic html/http concepts and layering some smart JavaScript on top of that.
To return the favor, here's a couple docs I found helpful:
https://remix.run/docs/en/v1/tutorials/jokes - this is their advanced tutorial and it's a bit long but once you get past the setup steps it's a really well written introduction to the concepts of remix through useful examples. One of the better tutorials I've ever read.
And then two of their technical docs which are a bit hidden in their site but useful: https://remix.run/docs/en/v1/pages/philosophy
https://remix.run/docs/en/v1/pages/technical-explanation
The key concepts is remix is understanding the loader(), UI component, and action() interactions and how those work with minimal code changes in: 1) server side only mode (with only raw html served) 2) server + smart JS client mode
It’s the good old server templates (we use Jinja), and for interactivity I have additional attributes here and there, and sometimes additional endpoints.
It’s miles better than full-fledged JS SPA. I’ve had React+GraphQL app that I’m migrating piece by piece when we need a new feature, and it’s a few times faster to do and easier to understand.
I thought it was just laziness from my side of not wanting to set up the whole react scene
Nice to have a name for it
This reminds me of the era before AJAX when we used to POST to a hidden iframe, and then JS in the hidden iframe would update the parent page.
When doing a "full page refresh" my browser has good UX for displaying errors and retrying requests, potentially resending <form> data. SPAs don't have any of that.SPAs is a cool pattern but as long as it is not supported by the HTML/CSS specs (and therefore the browser natively) it will remain terrible from a UX perspective.
But hindsight is 20/20. Someone may be building a beautiful language that will kill JS in the 2020s, and in 2026 we'll all be wondering why weren't using it in in early 2022.
the core idea is to use hypermedia, rather than an RPC-style architecture, and that is, at the least, an interesting alternative approach to consider when creating front end code
Since we began using this approach, we can be full-stack developers again. One person can easily implement both parts, which is so much faster.
Now, take my words with a grain of salt because i'm unaware of the details, but i don't see a reason HTMX couldn't support XML with proper schemas which would be great:
- for structured/typed data and ensuring proper API protocol negotiation between client and server
- for data structures closer to the DOM model (which has both fields and children for most elements, while a JSON key can point to a list or an object, not both)
- for serialization formats the browser knows about and is optimized for
- for interoperability with other systems/protocols based on XML schemas, such as XMPP
Data can be served in many forms. Your API could be a DNS key-value server, or a JSON endpoint, or a HTML page. Just because most people don't structure their HTML semantically doesn't mean it can't (or shouldn't) be done, which means you don't loose "access to data as data".
On the contrary, designing your API as semantic/structured HTML empowers users to parse/script your website to better suit their needs, whether that's for accessibility purposes or for developing 3rd party clients. Something that's become almost impossible in the age of SPAs and CAPTCHAs imposing the developer's will on my browsing experience.
I understand the appeal of what they are laying out here. I'm just wondering why the htmx approach has more benefits over the HATEOAS approach of something like API Platform that I linked to, which doesn't have any opinion on something being an MPA, SPA, or something in between
Also to clarify: I mean proprietary as in proprietary to htmx, this is a poor word choice on my part, no different to how Vue has its Single File Components which are "proprietary" to Vue. I'm specifically trying to understand the advantage of something that ties your APIs to markup rather than using an interchange format such as JSON, as such when building scalable systems it not uncommon to need some form of interchange functionality. Even at a smallish company I work for we need to make sure it is digestible on web, and mobile applications.
I'm just trying to apply some intellectual rigor to the model, as something I do think about is scaling, not say, Instagram Scale, even just something like a company with a 100+ million ARR may bubble these concerns
My understanding is that HTMX is based on the HATEOAS approach: https://htmx.org/essays/hateoas/
About API Platform you linked to, the homepage is not very clear (full of buzzwords but little info) but it appears to be a Backend+Frontend framework/distro based on PHP+JavaScript. Compared to that, HTMX is an HTML extension (just additional fields in the markup) which any backend/frontend can implement: even web browsers which don't have a JS runtime could implement HTMX and that's pretty cool.
> I mean proprietary as in proprietary to htmx
I believe HTMX is free software and i don't see a reason the specification can't be implemented by other projects. It's therefore not proprietary in my definition of the word.
> something that ties your APIs to markup rather than using an interchange format such as JSON
HTML/XML isn't that different from JSON. Just like your markup can evolve with your data structures and use-cases, so can your JSON. If you want interoperability, you should probably be using XML/JSON schemas and API versioning.
With something like htmx + hyperscript, the logic is tied to the components that are actually using them.
I am trying to popularize the term "Locality of Behavior" (LoB) to describe this property in software:
We can easily create endpoints that will respond with JSONs for mobile apps and with partial HTML for our hypermedia-driven application. The code is the same, just in the end check headers and render a template if we need to.