3 IRL use cases for Python and HTMX
This is not a sponsored post but feel free to send money anyway
Summary
There is nothing HTMX does that you couldn't do in another way. But HTMX pairs wonderfully with traditional server side frameworks and gives you clean, correct, results quite fast. You won't get candy crush bling level with it, but you will get something practical, which is regularly all what I need.
I added it to a quick and dirty dev tool so that it could be dynamic with little cost.
I sparkled it on a personal time management tool to force it to send standard requests.
And I sold it to my "not-so-good-coder" friend to make our team happier.
If at this point you are too afraid to ask...
Beyond the few months of hype and the hilarious twitter account, HTMX has proven to be a valuable addition to my toolbox.
But I read again and again people wondering what use case would you find that couldn't be done in a different way?
What the heck are those people laughing at grug memes using that stuff for?
First, let's make clear things up: there is nothing HTMX does that you couldn't do in another way. It's not HTMX vs .. It's HTMX also...
You add the tool to the ones you can use depending on the situation.
Yes, it's funny to make jokes on obese client side stacks, complicated build workflows and so on.
But of course, we use them too. That's why it cracks us up.
While I'm a Python expert, I am very comfortable with Javascript, and use React and Vue for my clients.
What's more, if you started web dev after 2015, it is very hard to see how to do a site with anything other than client side frameworks. But if, like me, you started in the Internet Explorer 6 era, it's just modernized common sense, with a little bit of sass.
Not the CSS tool. I mean sassy.
HTMX is a good tech if you know how to wield it. It's not going to change the destiny of humanity forever, and it does require the coder to think like PHP 3 is a thing again, but it has a lot of good things going on for it.
Mostly, it keeps the simple things simple. And that's pretty nice.
About the use cases
Before we start with the use cases, again, I must insist there is nothing in those that could not be made in another way. You may think, "oh, but I would have just..." and you would probably be right.
It's not about "the best way".
It never is in engineering.
It's about what was right for me and my context.
So while reading them, takes that in consideration. I'm not trying to sell HTMX to you, nor pry whatever tool you use instead from your hand. I'm just sharing.
Use case 1: a quick and dirty dev tool
Working for $main_client, we started to have quite a sized core lib dedicated to tricky calculations. One of my colleagues told me it would be nice, if, on top of the unit tests, we could have a UI with all the params, so that an intern could play chaos monkey on it and see what she finds.
Since they already had Fast API in their requirement files, a web UI made sense. But I started to think that if I created a new endpoint for this, then I needed to make the whole logic in JS. Which means adding JS to a project that has been so far a pure headless Python core.
It seemed unnecessary, so I just went with a regular HTML form + table with a Jinja template. It's simple, fast to make, and as a bonus, I could make the form emit a GET request, so that the intern could send us the URL and we could copy/paste it to replicate any bug on our side.
It was easy to code, uncomplicated. Nice.
At some point, though, the intern was annoyed she had to click a button to see the new results after changing a value. She was used to apps that were automatically updating on her phone, after all.
A bit of JS, and voilà, addEventLister
submits the form on change, and we are happy.
But again the intern was not pleased, changing one field would reload the page but dismiss her focus on inputs.
Ok, I was not going to do a full collection of the fields, submit them, get back the data and reinject them manually in the page. Not to mention it would mean crafting the URL manually to push it into the history. Especially given the delta of money the client spent on the intern vs me.
So as a good lazy boï, I just fired HTMX. The form now makes an invisible GET request on submit, fetches the very same page, extracts the table, replaces the old one, and update the URL dynamically. All that for typing 3 lines.
I had to type one script tag and 6 attributes to solve all problems at once:
<form hx-select="table" hx-target="table" hx-get="." hx-replace-url="true" hx-trigger="change" hx-swap="outerHTML" ...>
As a bonus, I said bye bye to my lone addEventLister
.
Rose are red. My client is happy. Now I can play Baldur's Gate 3.
Use case 2: a personal time management tool
I started a new habit. Any time I spent playing games or watching TV shows, I had to spend an equivalent time being physically active. Given I already practice some sport almost every day, that mostly results in less screen time, or me being too exhausted to go grab a drink with friends.
But tracking this is annoying. So I made what all good devs would do, I spent hours writing an app to save myself a few seconds.
Again, since it's just for me, I have zero incentive to spend a lot of time making a killer UI. One button to consume potato time, one button to top it up. That's not rocket science, and apart from a few lines of Alpine.js to make a timer (which pairs wonderfully with HTMX), I could go full server side and get this:
Everything was working fine, but I had to send POST requests for everything. And that bothered me.
It's completely pedantic, but having actions in my URLS instead of using the correct HTTP verbs just doesn't feel right.
Did I need HTMX? No. It worked.
Did I want HTMX? Yeah...
<button type="button" hx-put="/transactions/recharge/" >
Stop & save
</button>
And that's it. Now I have real organic DELETE/PUT requests, and I feel good. Plus my Django views blocks are beautifully segregated.
Use case 3: working with my best nemesis
I have a very old friend and we work on side projects all the time. He is a terrible programmer, and he hates code. But he loves the results, in the same way some people hate running but like feeling in shape, so he made some web sites, and basically live off them.
Working with him is a blessing and a curse. On one side, his code is dirty, he has refused to learn git basics for 10 years and just ask me every time what to do, and will blindly copy/paste in a frenzy everything that comes out of stackoverflow and chatgpt until something seems to work.
On the other hand, he is incredibly hard-working (way more than I will ever be), has a great sense of pragmatism and a lot of experience with b2c customers. He keeps me grounded.
We make a great team, I clean up his mess, and he keeps the project on track. Plus it's just fun to be together, feels like being 14 years old again.
But forget about a fancy stack.
Every new project is an occasion, not to add something, but to remove something.
I use doit to abstract the entire project management for him.
I keep finding ways to make the client side simpler and simpler for him, as he usually makes the UI. We just moved to tailwind, and he loves it. The templates are huge walls of infinite class blocks repeated ad nauseam.
But having to make an API call every time he needs some data... not some much.
He is not comfortable with asynchronous workflows, the promise API is still a vague mystery after a decade of it, plus, depending of the framework, where to put the AJAX calls? Don't mention hooks! He just came out of jQuery.
So I write the client, I wrap it up in an object, I place it in the Vue or React component, and we are BNF again.
Everything is kinda like this in the project.
This time, no more. I just went full HTMX.
He got the concept quickly, and now he is autonomous on his side of the project, meaning I can focus on the other things.
He doesn't have to wonder if something is mounted, what is this await
or if he has to write account-color
, accountColor
or account_color
. No more state management outside of the DB. One single routing for everything. Permissions and sanity are checked once.
Plus it works with flask, Django or FastAPI all the same. Something you can't say about sending back decent JSON.
There is no real conclusion
As you noticed, there is never a need for HTMX.
But I was satisfied with the result every time I chose to use it.
I didn't stop to use React, Vue and axios. I didn't stop using vanilla JS or alpine. I actually sometime mix them with HTMX.
I do use HTMX more and more, because it produces fast acceptable results. I do value a short feedback loop.
If you feel like giving the tech a try, we have a little tutorial for you.
Yes! Yes! But also, no.
Prime brought me here