Why I use htmx

By

Why I use htmx as the H in my AHA Stack: it lets any element trigger an HTTP request and ship HTML over the wire, so I write far less client-side JavaScript.

~~~

I introduced the notion of the “AHA Stack” - a set of tools I’ve been using with great satisfaction to create things on the Web. I updated ahastack.dev for htmx 4 if you want the current docs and demos.

A big, probably the most novel, thing in the AHA Stack is the H part: htmx.

htmx is a super interesting library.

Indie (not provided to you by a FAANG), simple, written in a single JavaScript file, around 2,400 lines in htmx 4, with no build step, htmx defines itself as an “extension of HTML”.

It brings a few brilliant ideas.

In particular I can mention it makes it possible that:

Those 3 ideas alone are genius.

Plus, we have the biggest change in thinking compared to traditional JS frameworks: you ship HTML over the wire.

Here is that model in a few attributes. A button can send a POST, even though it is not a form. The server answers with HTML, and htmx puts that HTML into the page:

<button
  hx-post="/cart/add"
  hx-target="#cart"
  hx-swap="innerHTML">
  Add to cart
</button>

<div id="cart"></div>

Click the button. htmx sends POST /cart/add. Whatever HTML the server returns is swapped into #cart. innerHTML is the default swap, so you could omit hx-swap here. I leave it in so the swap is visible in the markup.

There is no fetch() in your page, and no client template that rebuilds the cart from JSON. The button is the request, and the HTML coming back is what you show.

Using those ideas I can create interactions and experiences that would otherwise require me to write a ton of JavaScript, depend on a big pile of JavaScript dependencies and hundreds of npm packages, to execute a ton of JavaScript on the client side.

It’s a brilliant little library, with no dependencies, that you install through a script tag. It’s backend-agnostic.

We use htmx to handle client-server HTTP communication once the page is loaded.

So for example the user clicks a link, and we load some data from the server, which we get back as HTML, and we add it to the page dynamically.

And we do this in a way that’s declarative.

Not imperatively writing JavaScript to tell the page what to do, instead, we go up a level of abstraction, and declare what we want it to do.

When I don’t use htmx

htmx is a bad fit when the interesting state lives in the browser.

A drawing canvas, a spreadsheet, a live editor, an offline-first app: those keep changing without a round trip. Pushing every keystroke or drag through the server fights the problem.

I also wouldn’t use it as the only front end when a mobile app already consumes the same JSON API. Then I’d be maintaining HTML fragments and JSON for the same actions. htmx wants the server to return the interface, not a dump of records.

Small bits of client-only UI still need JavaScript. Opening a dropdown, toggling a class, reading localStorage. That’s why Alpine.js sits next to htmx in the AHA Stack. If the page is mostly that kind of local state, Alpine (or just a bit of JS) is enough and htmx has nothing to request.

And every htmx action is a network call. Fine for a form or a search box. Painful if you need instant local feedback, or if the server is far away and you’re swapping big chunks on every click.

For the apps I actually build, that’s the exception. Most of them are pages, forms, and lists, and those are the ones htmx is for.

Tagged: htmx · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about htmx: