htmx 4.0 ist da
htmx 4.0 ändert Vererbung, Fehler-Swaps, Verlauf und Events und bietet Migrationshinweise sowie Rückfalloptionen für htmx-2-Apps.
htmx 4.0.0 wurde am 28. August 2026 veröffentlicht. Damit ändern sich mehrere seit Langem etablierte Standardeinstellungen: Attributvererbung ist jetzt opt-in, Fehlerantworten werden ins DOM geswappt, und der History-Snapshot-Cache ist Geschichte.
Wenn Sie eine htmx-2-Anwendung betreuen, lautet die praktische Frage: Schützt das hx-confirm, das Sie vor zwei Jahren auf einen Container hochgezogen haben, nach dem Upgrade überhaupt noch irgendetwas? Nein – es sei denn, Sie ergänzen einen Modifier. Dieser Beitrag behandelt, was bricht, womit sich die jeweilige Änderung rückgängig machen lässt, und warum die npm-Release-Strategie dafür sorgt, dass Sie diese Woche vermutlich noch nichts tun müssen. Was htmx überhaupt ist und warum Hypermedia – das deckt der htmx-2.0-Walkthrough ab, auf dem dieser Artikel aufsetzt.
Die wichtigsten Erkenntnisse
- htmx 4 macht Attributvererbung über den Modifier
:inheritedexplizit; wirdhtmx.config.implicitInheritanceauftruegesetzt, stellt das als Migrationsbrücke das Verhalten von htmx 2 wieder her. - In htmx 4 überspringen standardmäßig nur noch
204- und304-Antworten den Swap, sodass ein serverseitig gerendertes422jetzt im Target landet, statt verworfen zu werden;htmx.config.noSwap = [204, 304, '4xx', '5xx']macht das rückgängig. - Event-Namen folgen dem Muster
htmx:phase:action, wofür es keinen Config-Schlüssel gibt: Jeder htmx-Listener in Ihrem JavaScript muss umbenannt werden – oder Sie installieren die Extensionhtmx-2-compat. - Benennen Sie
hx-disablevor dem Upgrade inhx-ignoreum, denn htmx 4 vergibt den Namenhx-disableneu für die Aufgabe, die bisherhx-disabled-eltübernommen hat. - htmx 2.x behält den npm-Tag
latest, während 4.0 unternextliegt. Unversionierte CDN-URLs werden also nicht zwangsweise aktualisiert, und laut Ankündigung wird htmx 2 auf unbestimmte Zeit unterstützt.
Was hat sich in htmx 4 geändert?
htmx 4 stellt die Request-Internals der Bibliothek von XMLHttpRequest auf fetch() um, und genau dieses Rewrite hat den Rest des Releases erst möglich gemacht. Der Wechsel des Transports war ohnehin ein Breaking Change, also hat das Team dasselbe Major-Release genutzt, um Defaults zurückzusetzen, die sich seit htmx 1 angesammelt hatten.
Beim Schreiben von htmx rufen Sie keine der beiden APIs direkt auf, der Transportwechsel selbst ist in Ihren Templates also unsichtbar. Die Folgen zeigen sich an den Rändern: Die XHR-spezifischen Lifecycle-Events haben kein Äquivalent in fetch() und wurden entfernt, und htmx 4 setzt htmx.config.defaultTimeout auf 60000, wo htmx 2 einen Request unbegrenzt hängen ließ.
Zur Versionsnummer: htmx-Schöpfer Carson Gross hatte erklärt, es werde nie ein htmx 3 geben – das Release springt also direkt auf 4.0, und das Versprechen überlebt aus formalen Gründen. Die Begründung legte er im Essay dar, mit dem er das Rewrite ankündigte (November 2025).
Attributvererbung ist jetzt explizit
Vererbung findet in htmx 4 nur noch statt, wenn Sie sie anfordern. Ein Attribut auf einem Container gilt ausschließlich für diesen Container, sofern Sie nicht den Modifier :inherited ergänzen – und dieser Modifier funktioniert bei jedem Attribut: hx-boost:inherited, hx-target:inherited, hx-confirm:inherited.
<!-- htmx 4: the confirm reaches both buttons -->
<div hx-confirm:inherited="Are you sure?">
<button hx-delete="/account">Delete My Account</button>
<button hx-put="/account">Update My Account</button>
</div>
Ein Wert auf einem Kindelement setzt sich standardmäßig gegen den geerbten durch. Verwenden Sie :append, wenn Sie stattdessen beide kombinieren wollen – das ist der Kompositionsfall, über den viele stolpern:
<div hx-vals:inherited="tenant:acme">
<button hx-post="/save" hx-vals:append="source:save-btn">Save</button>
</div>
Ohne :append tritt das eigene hx-vals des Buttons an die Stelle des geerbten, und tenant erreicht den Server nie. Setzt kein Vorfahre das Attribut, ist der angehängte Wert der einzige, der gesendet wird. Die Bezeichnungen variieren je nach Attribut leicht: Die Referenzseite zu hx-disable dokumentiert für dieselbe Aufgabe – das Ergänzen eines Elternwerts – :merge.
hx-inherit und hx-disinherit wurden entfernt, da explizites Opt-in beide überflüssig macht. Wenn Ihre Templates auf dem alten Verhalten aufbauen, setzen Sie htmx.config.implicitInheritance auf true, um es während der Migration wiederherzustellen. Betrachten Sie das als Brücke, nicht als Ziel.
Fehlerantworten werden standardmäßig geswappt
In htmx 4 erreicht eine Antwort das Target unabhängig von ihrem Statuscode, nur 204 und 304 werden zurückgehalten. Eine serverseitig gerenderte 422-Validierungsseite landet nun im Target, statt stillschweigend verworfen zu werden – genau das, was Hypermedia-Anwendungen von jeher wollten. Eine HTTP-Fehlerantwort löst zusätzlich ein htmx:response:error-Event aus.
Das neue Attribut hx-status leitet einzelne Codes an ein eigenes Target und einen eigenen Swap weiter:
<form hx-post="/submit"
hx-target="#result"
hx-status:422="target:#validation-errors"
hx-status:5xx="target:#server-error"
hx-status:503="swap:none">
<input name="email">
<button type="submit">Submit</button>
</form>
htmx probiert zuerst das spezifischste Muster: den exakten Code, dann ein Muster mit maskierter letzter Ziffer wie 50x, dann eines mit den letzten beiden maskiert wie 5xx. Innerhalb des Attributwerts lassen sich swap:, target:, select:, push:, replace: und transition: setzen.
Wenn Ihr Backend Fehlerseiten zurückgibt, die nie zum Swappen gedacht waren, setzen Sie htmx.config.noSwap auf [204, 304, '4xx', '5xx'] – und Sie haben das Verhalten von htmx 2 zurück.
Zurück-Navigation ist jetzt ein echter Request
htmx 4 verzichtet auf den clientseitigen DOM-Snapshot-Cache, der die History in htmx 2 gestützt hat. Beim Klick auf „Zurück” fordert htmx die Seite erneut vom Server an und swappt das Ergebnis in <body> – oder in ein [hx-history-elt]-Element, sofern die Seite eines besitzt.
Praktisch bedeutet das: Der Zurück-Button zeigt, was der Server aktuell als Seiteninhalt liefert, und nicht einen Snapshot, der im Moment des Wegnavigierens eingefroren wurde. Damit entfällt eine ganze Fehlerklasse, bei der Drittanbieter-Skripte das DOM mutiert haben und der wiederhergestellte Snapshot diese Mutationen in einen kaputten Zustand zurückgespielt hat. Es bedeutet aber auch: Zurück-Navigation kostet einen Request.
Das Attribut hx-history ist zusammen mit dem Cache verschwunden. Wenn Sie Snapshots brauchen, führt die Core-Extension hx-history-cache sie als Opt-in wieder ein.
Event-Namen folgen dem Muster htmx:phase:action
Sämtliche htmx-Lifecycle-Events wurden auf die Form htmx:phase:action[:sub-action] umbenannt. Die Ankündigung nennt htmx:beforeRequest als htmx:before:request und htmx:beforeSwap als htmx:before:swap; aus htmx:afterSwap wird htmx:after:swap.
Das ist die eine Änderung ohne Konfigurations-Notausgang. Jeder Listener muss angepasst werden:
// htmx 2
document.body.addEventListener('htmx:afterSwap', (e) => {
initTooltips(e.detail.target);
});
// htmx 4
document.body.addEventListener('htmx:after:swap', (e) => {
initTooltips(e.detail.target);
});
Die meisten Fehler-Events sind in htmx:error zusammengefasst, wobei HTTP-Fehlerantworten htmx:response:error auslösen. Die XHR-spezifischen Events sind schlicht weg, da fetch() kein Äquivalent bereitstellt. Wenn das händische Anpassen der Listener den Hauptteil Ihrer Migration ausmacht, bildet die Extension htmx-2-compat die alten Event-Namen auf die neuen ab und stellt zusätzlich implizite Vererbung sowie hx-ext wieder her.
Was ist in htmx 4 neu – und nicht nur kaputt?
Drei Neuerungen in htmx 4 rechtfertigen das Upgrade schon für sich: Morph-Swaps, das Element <hx-partial> und die neu geschriebenen Streaming-Extensions. Morph-Swaps stecken im Core, zustandserhaltende DOM-Updates brauchen also keine Extension mehr. Das Element <hx-partial> erlaubt es einer einzigen Antwort, mehrere Targets zu aktualisieren, wobei jedes sein eigenes Target und seinen eigenen Swap mitbringt:
<hx-partial hx-target="#messages" hx-swap="beforeend">
<div>New message</div>
</hx-partial>
<hx-partial hx-target="#count">
<span>5</span>
</hx-partial>
Da Target und Swap-Stil am Partial selbst hängen, gibt die Antwort an, was mit jedem einzelnen Stück geschehen soll – statt dass Sie es aus im Markup verstreuten hx-swap-oob-Attributen erschließen müssen. Beachten Sie, dass sich die Reihenfolge bei Out-of-Band-Swaps in htmx 4 umgekehrt hat: Der Hauptinhalt wird zuerst geswappt.
Die Streaming-Extensions sind die zweite große Neuerung. Sowohl die SSE- als auch die WebSocket-Extension wurden für dieses Release neu gebaut, und eine ganze Reihe neuer kommt hinzu: hx-multipart, hx-live, hx-targets, hx-ptag, hx-csp, hx-download, hx-prompt und hx-history-cache. Verbindungsattribute sind namespaced, SSE verbindet sich also über hx-sse:connect und WebSockets über hx-ws:connect.
Das Upgrade auf htmx 4 – und warum es nicht eilt
Das Upgrade auf htmx 4 beginnt mit dem Scanner: Führen Sie ihn aus, bevor Sie irgendetwas planen. npx htmx.org@4.0.0 upgrade-check -- ./path/to/project/root durchläuft Ihr Projekt und gibt jedes veraltete Pattern mit Datei und Zeilennummer aus – genug, um den Aufwand an einem Nachmittag abzuschätzen.
npx htmx.org@4.0.0 upgrade-check -- ./templates
npx htmx.org@4.0.0 upgrade-check --ext .vue ./path/to/project/root
Standardmäßig betrachtet er .html, .php, .js, .ts, .jinja, .jinja2, .j2, .erb und .hbs. Single-File-Component-Formate gehören nicht dazu, .vue-, .svelte-, .jsx- und .astro-Templates bleiben also ungeprüft, sofern Sie nicht --ext übergeben.
Eine Umbenennung sollten Sie vor allem anderen erledigen: Aus hx-disable wird hx-ignore, und aus hx-disabled-elt wird hx-disable. Der alte Name wird für eine andere Aufgabe wiederverwendet – migrieren Sie also zuerst hx-disabled-elt, überschreiben Sie Attribute, die noch die htmx-2-Bedeutung tragen.
| Änderung | Standard in htmx 4 | Wiederherstellung von htmx 2 |
|---|---|---|
| Attributvererbung | Explizit, über :inherited | htmx.config.implicitInheritance = true |
| Swapping von Fehlerantworten | Nur 204/304 überspringen den Swap | htmx.config.noSwap = [204, 304, '4xx', '5xx'] |
| History | Erneuter Server-Abruf beim Zurück | Extension hx-history-cache |
| Event-Namen | htmx:phase:action | Kein Config-Schlüssel; Extension htmx-2-compat |
Und dann der Punkt, der entscheidet, ob das alles überhaupt dringend ist: Auf npm hält htmx 2.x den dist-Tag latest, während 4.0.0 unter next veröffentlicht ist. Die Ankündigung stellt ausdrücklich klar, dass das Absicht ist, damit Seiten, die htmx über eine unversionierte CDN-URL laden, nicht zwangsweise in Breaking Changes hineinaktualisiert werden – 2.x bleibt bis Anfang 2027 auf latest. 2.x wird auf unbestimmte Zeit weiter unterstützt.
Daraus ergeben sich vier Ausgangslagen. Eine unversionierte CDN-URL liefert weiterhin 2.x aus, bis der Tag umgestellt wird – der einzige Fall mit einer Deadline in der Zukunft. Eine gepinnte CDN-URL und ein exakter npm-Pin ändern sich nie von selbst. Ein npm-Range wie ^2.0.0 bleibt unabhängig von dist-Tags innerhalb von 2.x. Um 4.0 heute zu installieren, pinnen Sie es: npm install htmx.org@4.0.0, oder nutzen Sie den versionierten CDN-Pfad.
Neue Projekte starten Sie mit 4.0. Bei einer bestehenden htmx-2-Anwendung: Scanner laufen lassen, zuerst die hx-disable-Umbenennung durchführen und anhand der Länge des Reports entscheiden, ob Sie jetzt migrieren oder die Sache vor der Umstellung des dist-Tags erneut angehen.
FAQs
Wie lade ich eine htmx-Extension in htmx 4, jetzt wo hx-ext entfernt wurde?
Binden Sie das Extension-Skript nach dem htmx-Skript ein; seine Attribute funktionieren sofort, ohne aktivierendes Attribut. Laden Sie dist/ext/hx-sse.js neben htmx.min.js, und Sie können hx-sse:connect direkt verwenden. Die Distribution htmax.js liefert htmx samt den beliebtesten Extensions vorgebündelt in einer einzigen Datei aus, wobei diese Attribute automatisch verfügbar sind. Extension-Autoren registrieren sich über htmx.registerExtension mit einem Namen und einer Method-Map.
Kann ich den zusätzlichen Server-Request vermeiden, den htmx 4 bei der Zurück-Navigation auslöst?
Ja. Die Core-Extension hx-history-cache stellt die History aus dem sessionStorage wieder her, statt einen vollständigen Server-Request abzusetzen – das kommt den Snapshots aus htmx 2 am nächsten. Alternativ ändern zwei Konfigurationswerte das Verhalten: htmx.config.history auf 'reload' führt bei History-Navigation einen kompletten Seiten-Reload durch, und htmx.config.history auf false deaktiviert die History-Behandlung. Der localStorage-Snapshot-Cache aus htmx 2 ist entfallen.
Was ersetzt hx-vars und hx-prompt in htmx 4?
hx-vars wurde entfernt; berechnete Werte wandern zu hx-vals mit dem Präfix js:. hx-prompt ist aus dem Core entfernt und wird als Extension ausgeliefert: Laden Sie die Extension hx-prompt, um dieselbe Syntax beizubehalten. Weitere entfernte Attribute sind hx-ext, hx-inherit, hx-disinherit und hx-history. hx-disabled-elt wurde umbenannt statt entfernt: Es wird zu hx-disable, und das bisherige hx-disable wird zu hx-ignore – so legt es die Umbenennungstabelle in [What's New in htmx 4](https://four.htmx.org/docs/whats-new-in-htmx-4) dar. Der Scanner upgrade-check kennzeichnet diese beiden als renamed-attr und die tatsächlichen Entfernungen als removed-attr, jeweils mit Datei, Zeilennummer und vorgeschlagenem Ersatz.
Funktioniert hx-swap-oob in htmx 4 noch, und wann sollte ich stattdessen hx-partial verwenden?
hx-swap-oob funktioniert weiterhin, allerdings dreht htmx 4 die Reihenfolge um: Der Hauptinhalt wird zuerst eingefügt, Out-of-Band- und hx-partial-Elemente folgen in Dokumentreihenfolge. Greifen Sie zu hx-swap-oob, wenn Sie ein Element gegen eine aktualisierte Kopie desselben Elements austauschen, und zu hx-partial, wenn eine einzelne Antwort mehrere Stellen aktualisieren muss – denn jedes Partial gibt sein eigenes hx-target und hx-swap an, statt sich auf im Markup verstreute Attribute zu stützen.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k