An HTMX success story
For a long time, if you wanted to build a modern, SPA-like frontend for a Python web app, the natural choice was to reach for a heavy web frontend framework or library. Something like React or one if it's many many competitors.
The architecture would be something like:
You'd have a Python application at the back, expose a bunch of APIs, and then have a totally separate application just for the web frontend. This seems simple enough, but it's much more complicated than it needs to be.
I built something like this - I built a learner management system using Django and React. The relevant parts of the stack were:
Frontend:
- MaterialUI: A component library for making the GUI look goodish
- React: Web frontend library
- Redux: Frontend state management
- Redux Saga: Side effect management for redux
Backend:
- Django Rest Framework: For exposing RESTish APIs
- Django: Ol' faithful web framework
- Django-Guardian: for object level permissions on Django model instances, for securing api endpoints
- Postgres database
You can see a link to a conference talk I did about it here:
It works great...
But...
The challenge with this type of architecture is that building a single full stack feature requires a lot of different skills. For a developer to simply display a little data on the frontend, or make a simple button work, they would need to know at least a little bit about every part of the stack.
That's a lot of different skills. A lot of context switching. A lot of moving parts. To get even the simplest full-stack feature working, end to end, you'd need to write code for multiple applications that do totally different things in totally different ways.
This is completely fine if you are in a position where you are able to get relatively good at all the different tools, and understand their interplay. But inexperienced devs can really struggle with this.
My little dev team
Due to the nature of my work, I had a very junior heavy dev team. It was quite unreasonable to expect a junior dev to be able to grok every aspect of the stack. So even getting the simplest full stack feature up and running was an ordeal.
The best ways I could find for getting people productive was to write a bunch of code myself and then let the juniors finish off features, or break features down into separate little tasks so that the juniors could practice specific skills in specific places.
Things took ages to build, and the juniors needed a lot of support.
Enter HTMX
I was struggling to get my team to be productive and had more or less come to the sad conclusion that junior devs just would not be useful if we wanted to build a modern web app.
And then I went to DjangoCon US and saw a brilliant talk on HTMX.
HTMX is not yet another heavy and complicated web frontend framework. It is a tiny JavaScript library that allows you to add SPA-like behavior to plain ol' HTML just by making use of a few HTML tag attributes.
Basically what HTMX does is listen to DOM events and then trigger AJAX requests based on those events. The responses from the requests should be fragments of HTML (not JSON data structures). HTMX then takes the response HTML and puts it where you want to to go.
Here's an example from the official docs:
<button hx-post="/clicked" hx-swap="outerHTML">
Click Me
</button>
This example listens for a click event, you could listen to a different event if you wanted. Eg scroll, onload, etc.
When the user clicks the button then a POST request is sent to a specific url. You could use a different request verb and a different url, and you can send parameters with yor request.
Once the response is received, HTMX takes the body (which is HTML) and replaces the button with the HTML. You can target any DOM element you want, and you can choose to do other things besides just replacing existing HTML with new HTML.
This is great because it is dead simple, and it's very powerful.
Missing pieces
HTMX is wonderful, but there are some things it can't do. For example, state management. Alpine.JS is great for that.
Like HTMX, Alpine allows you to specify "modern" web frontend behavior by making use of a few HTML tag attributes.
Basically what it allows you to do is edit some simple HTML attributes to declare variables, then tie those variables to different DOM elements and events.
Here is an example from the official docs:
<div x-data="{ open: false }">
<button @click="open = true">Expand</button>
<span x-show="open">
Content...
</span>
</div>
It's immediately pretty clear what this code is meant to do. Again, this is dead simple, and very powerful.
Sufficient?
Choosing the technologies to build an application in is friggin difficult a lot of the time. There is a lot to consider. Two of those many many things are:
- The team. Can people learn and apply the skills? Can the skills be aquired some other way? Will the dev experience be good?
- The capabilities of the tools: Can the tools do the job. Will they keep doing the job.
Of course there are a great many other things, but I want to focus on just these two for now.
In my situation, I knew I needed to make some major changes to the tech stack or the team I was working with. Maybe both.
Changing the tech stack so that I would be using HTMX+Alpine.JS instead of React would be no small feat. And generally when people suggest a total rewrite of an application, I suggest they stop drop and roll. Most of the time it's not a great idea.
So this was a tough decision.
Capabilities of the tools
The first thing I did was take the tools for a spin myself.
The application I was working on was centred around a kanban board - That was the most complicated part of the application, the riskiest part. So I rolled up my sleeves, opened up the HTMX and AlpineJS documentation, and got to work.
Reimplementing the most complex frontend functionality I needed was not only possible, but actually pretty easy compared to the last version of the application. And pretty fun.
Hydration, pagination, moving cards between columns - it was all pretty straightforward. I was very quickly convinced that HTMX had the capabilities we needed.
Capabilities of the team
The next thing I did was set up a few tasks for the team to do. I got them to write some code using HTMX and AlpineJS and watched. They were waaay faster than before. They could do quite a lot with minimal guidance. Full stack features were in reach for even the most inexperienced member of my team.
Simple is better than complex
The argument can easily be made that if you optimize for noob developers when you choose your tech stack, you could be optimizing for the wrong thing. But I would say that it's always worth optimizing for simplicity.
If you choose technologies such that the most junior member of your team is able to add value, then that pays dividends all over the place. One of the main things I noticed was that my own dev productivity went through the roof.
With the new stack I could build something in minutes that would have taken hours before. And it was fun - I could get the work done quickly without needing to deal with any of the repetitive grind of getting multiple applications to play nicely together.
In short, every single developer on the team got a productivity boost.
The final stack
The final tech stack ended up looking like this:
- TailwindCSS: because beautiful is better than ugly
- AlpineJS: For dead simple state management
- HTMX: recommended by 9 out of 10 dentists
- Django: the framework for perfectionists with deadlines
- Postgres: in elephants we trust
The Django application server-side renders a bunch of HTML pages and fragments and serves those. It's dead simple compared to what we had before.
Then, since all the code sits within the Django app, we can test our frontend functionality using Playwright.
Benefits in brief
I've spoken about my reasons for changing to HTMX. There are a few other benefits forth mentioning.
- accessability is easy: Since you are writing HTML that is a lot like perfectly normal HTML, you can make sure you write stuff properly. This means things tend to be accessible by default
- network usage: The tools I'm talking about here are tiny, so that means that the client doesn't need to download anything heavy just for basic functionality
- lower needs for ram and compute, support crappier clients: These tools are super lightweight and so they are not resource intensive at all. This matters a lot to me because our users typically have pretty low-powered machines
- works on older clients: We dont need everyone to run the fastest and fanciest web browsers in order to work
For me the killer benefit of this stack is still developer productivity and happiness. For experienced devs, HTMX and AlpineJS are rocketfuel for productivity. And junior devs are able to get meaningful work done without significant oversight.
Want to learn from me?
I'm running some technical workshops over at Prelude. These are damn fine learning experiences.
If you or your team are likely to benefit from learning how to use these tools the fast way, join a workshop! Or reach out if you want training for your team!
Also, if you know someone who would benefit it would be very helpful if you shared a link and a kind word.
One of the major goals of offering training is to find sustainable ways to spread skills to folks that need help.
❤️ Thanks!
Moar reading
My siltation is in no way unique. Here are a few articles about other people porting from React to HTMX:
Want to join one of my upcoming workshops?
I run hands-on, small-group, expert-led, hyper-practical online workshops covering a variety of different tools and technologies.