HTMX 4 is here
By Flavio Copes
HTMX 4 moves to fetch, makes inheritance explicit, cleans up events and history, and adds morph swaps and multi-target partials.
HTMX 4.0.0 was released on August 28, 2026.
This is a major release, but HTMX is still HTMX.
You add attributes to HTML. Those attributes make HTTP requests. The server returns HTML, and HTMX puts that HTML into the page.
If HTMX is new to you, start with my free HTMX Course or my deep dive into HTMX. I also wrote about why I use HTMX in the first place.
I included HTMX as the H in the AHA Stack, together with Astro and Alpine.js. Astro renders the HTML, HTMX handles server requests and HTML updates, and Alpine.js manages small pieces of local state.
HTMX 4 keeps that model. Let’s see the major changes.
HTMX now uses fetch
HTMX used XMLHttpRequest because it once supported older browsers.
HTMX 4 replaces it with the browser’s native fetch() API.
For most applications, this is an internal change. Your hx-get, hx-post, targets, and swaps still work in the same way.
The new foundation makes streaming easier and gives extensions a cleaner way to work with requests.
Attribute inheritance is now explicit
This is the biggest change when upgrading an existing application.
In HTMX 2, some attributes on a parent automatically applied to its children:
<div hx-confirm="Are you sure?">
<button hx-delete="/items/1">Delete</button>
</div>
In HTMX 4, add :inherited when you want that behavior:
<div hx-confirm:inherited="Are you sure?">
<button hx-delete="/items/1">Delete</button>
</div>
An attribute placed directly on an element works as before.
I like this change. You can look at the parent and see that its behavior reaches the children. There is less invisible behavior to remember.
Event names are more consistent
HTMX 2 event names grew over time. They did not follow one clear pattern.
HTMX 4 events use htmx:phase:action:
| HTMX 2 | HTMX 4 |
|---|---|
htmx:beforeRequest | htmx:before:request |
htmx:afterRequest | htmx:after:request |
htmx:beforeSwap | htmx:before:swap |
htmx:afterSwap | htmx:after:swap |
htmx:configRequest | htmx:config:request |
Most request errors now use htmx:error. HTTP error responses use htmx:response:error.
If you listen to HTMX events in JavaScript or with hx-on, you must check those names during the upgrade.
History no longer stores page snapshots by default
HTMX 2 stored DOM snapshots in localStorage for back-button navigation.
That could save a page after another JavaScript library changed it. Restoring that snapshot did not always restore the JavaScript state behind it.
HTMX 4 fetches the page again when you go back. It then swaps the response into <body>, or into the element marked with hx-history-elt.
This removes a lot of hidden state. If you want local history caching, HTMX now provides the hx-history-cache extension.
Error responses are swapped by default
There is another upgrade detail worth knowing.
HTMX 2 did not swap 4xx and 5xx responses by default. HTMX 4 swaps every response except 204 and 304.
This is useful when your server returns validation HTML with a 422 status. But an existing application might return an error page that was never meant to appear inside a small target.
Check your error responses before upgrading. You can use hx-status when each status needs a different target or swap behavior.
Morph swaps are built in
A normal swap replaces part of the DOM.
HTMX 4 also includes innerMorph and outerMorph:
<button
hx-get="/profile"
hx-target="#profile"
hx-swap="outerMorph">
Refresh profile
</button>
A morph changes the existing DOM to match the new HTML. It can preserve things like focus, input state, and a playing video because it does not replace every node.
Morphing uses more CPU than a normal swap. I would use it where preserving DOM state matters, not as the default everywhere.
One response can update several targets
HTMX already supports out-of-band swaps. HTMX 4 adds a clearer option called <hx-partial>.
The server can return several updates, and each one names its own target:
<hx-partial hx-target="#messages" hx-swap="beforeend">
<div>New message</div>
</hx-partial>
<hx-partial hx-target="#message-count">
<span>5</span>
</hx-partial>
One response can append a message and update the counter. The intent is visible in the response itself.
Extensions got more interesting
HTMX 4 has a new event-based extension system.
There are extensions for preloading, file downloads, optimistic updates, Server-Sent Events, WebSockets, streaming multipart responses, and history caching.
The hx-alpine-compat extension is especially interesting for AHA Stack applications. It initializes Alpine.js on new fragments before HTMX swaps them into the page.
There is also an optional htmax.js bundle. It packages HTMX with its most popular extensions in one file.
How I would upgrade an AHA Stack application
I would not change everything at once.
First, I would run the official upgrade checker:
npx htmx.org@4 upgrade-check -- ./src
It finds inherited attributes, old event names, removed attributes, and old API calls. The tool requires Python 3.
Then I would make inheritance explicit and rename my event listeners. I would also inspect every 4xx and 5xx response that returns HTML.
HTMX includes an htmx-2-compat extension if an application needs a gradual migration. It restores old event names, implicit inheritance, and the previous error-swapping defaults.
After the application works, I would test morph swaps in parts of the interface where focus or local state matters. In an AHA Stack application, I would also test hx-alpine-compat anywhere an HTMX response adds Alpine.js components.
You can read the complete details in the official HTMX 4 migration guide.
You do not have to upgrade today
HTMX 2 will continue to be supported.
It also remains the latest npm release until early 2027. This avoids silently upgrading sites that use a CDN URL without a version.
To install version 4 now, ask for the major version explicitly:
npm install htmx.org@4
HTMX 4 feels like a careful cleanup, not a new framework.
That is exactly what I want from a library like HTMX.
Want me to talk about your product? You can sponsor this site.