</> htmx
🚧 htmx 4.0 is under construction. Read changes →

htmx 2.x → htmx 4.x Migration Guide

The purpose of this guide is to provide instructions for migrations from htmx 2.x to htmx 4.x.

htmx 4 is a significant architectural rewrite which involves breaking changes. We have tried to maintain backwards compatibility where possible but this upgrade will require more work than the htmx 1 to htmx 2 migration.

Biggest Changes

The three most impactful changes in htmx 4 are:

While there is no way to “undo” the first item in htmx 4, the second two changes can be undone by:

Making these to changes will make many htmx 2-based applications work with htmx 4 without further changes.

Attribute Changes

Renamed Attributes

htmx 2.xhtmx 4.xNotes
hx-disabled-elthx-disableBefore upgrading, audit usage of hx-disable attribute (see note below)

Important Note on hx-disable:

In htmx 2, hx-disable disables htmx processing. In htmx 4, hx-ignore serves this purpose. Before upgrading:

  1. Search for any usage of hx-disable in your htmx 2 codebase
  2. Rename hx-disablehx-ignore
  3. Then rename hx-disabled-elthx-disable

Removed Attributes

The following attributes have been removed:

Removed Attributehtmx 4 Alternative
hx-varsUse hx-vals with js: prefix
hx-paramsUse htmx:config:request event to filter parameters
hx-promptUse hx-confirm with async JavaScript function
hx-extExtensions now work via event listeners
hx-disinheritNo longer needed (inheritance is explicit)
hx-inheritNo longer needed (inheritance is explicit)
hx-requestUse hx-config
hx-historyRemoved (history is no longer stored in local storage)
hx-history-eltRemoved (history uses target element)

New Attributes

AttributePurpose
hx-actionSpecifies URL (use with hx-method)
hx-methodSpecifies HTTP method (use with hx-action)
hx-configConfigure request behavior with JSON

Attribute Inheritance Changes

Inheritance is now, by default, explicit using the :inherited modifier.

Before (htmx 2):

<!-- Attributes inherited automatically -->
<div hx-confirm="Are you sure?">
    <button hx-delete="/item/1">Delete 1</button>
    <button hx-delete="/item/2">Delete 2</button>
</div>

After (htmx 4):

<!-- Must use :inherited modifier -->
<div hx-confirm:inherited="Are you sure?">
    <button hx-delete="/item/1">Delete 1</button>
    <button hx-delete="/item/2">Delete 2</button>
</div>

Any attribute can use the :inherited modifier: hx-boost:inherited, hx-headers:inherited, hx-target:inherited, etc.

As mentioned above, you can revert this behavior by setting htmx.config.implicitInheritance to true

GET/DELETE Form Data

In htmx 4 hx-delete, like hx-get, no longer includes the enclosing form’s inputs by default. Use hx-include="closest form" if you need this behavior.


Event Name Changes

htmx 4 uses a new event naming convention: htmx:phase:action[:sub-action], and so if you are using htmx events you need to rename the events that they are listening for. Here is a complete table with the htmx 4 equivalent events:

htmx 2.x Eventhtmx 4.x EventNotes
htmx:afterOnLoadhtmx:after:init
htmx:afterProcessNodehtmx:after:init
htmx:afterRequesthtmx:after:request
htmx:afterSettlehtmx:after:swap
htmx:afterSwaphtmx:after:swap
htmx:beforeCleanupElementhtmx:before:cleanup
htmx:beforeHistorySavehtmx:before:history:update
htmx:beforeHistoryUpdatehtmx:before:history:update
htmx:beforeOnLoadhtmx:before:init
htmx:beforeProcessNodehtmx:before:process
htmx:beforeRequesthtmx:before:request
htmx:beforeSendhtmx:before:request
htmx:beforeSwaphtmx:before:swap
htmx:beforeTransitionhtmx:before:viewTransition
htmx:configRequesthtmx:config:request
htmx:historyCacheMisshtmx:before:restore:history
htmx:historyRestorehtmx:before:restore:history
htmx:loadhtmx:after:init
htmx:oobAfterSwaphtmx:after:swapNo separate OOB swap events
htmx:oobBeforeSwaphtmx:before:swapNo separate OOB swap events
htmx:pushedIntoHistoryhtmx:after:push:into:history
htmx:replacedInHistoryhtmx:after:replace:into:history
htmx:responseErrorhtmx:errorAll errors consolidated
htmx:sendErrorhtmx:errorAll errors consolidated
htmx:sendAborthtmx:errorAll errors consolidated
htmx:swapErrorhtmx:errorAll errors consolidated
htmx:targetErrorhtmx:errorAll errors consolidated
htmx:timeouthtmx:errorAll errors consolidated
htmx:validation:validateRemovedUse native form validation
htmx:validation:failedRemovedUse native form validation
htmx:validation:haltedRemovedUse native form validation
htmx:xhr:abortRemovedUse htmx:error event
htmx:xhr:loadstartRemovedNo fetch() equivalent
htmx:xhr:loadendRemovedUse htmx:finally:request
htmx:xhr:progressRemovedUse fetch() streams API if needed

XHR Upload Progress Events Removed

In htmx 2.x, the following XHR upload progress events were available:

These events provided detailed upload progress information with lengthComputable, loaded, and total properties.

In htmx 4.x these events have been removed because htmx now uses the fetch() API instead of XMLHttpRequest.

If you need upload progress tracking in htmx 4:

  1. Use the htmx:config:request event to access the request context
  2. Implement custom fetch with progress tracking using fetch streams or a library
  3. Consider using a specialized upload library for complex upload scenarios

New Events in htmx 4


JavaScript API Changes

The htmx JavaScript API has changed significantly in htmx 4.

Removed API Methods

The following JavaScript API methods have been removed in htmx 4:

htmx 2.x Methodhtmx 4 Alternative
htmx.addClass()Use native element.classList.add()
htmx.closest()Use native element.closest()
htmx.location()Use htmx.ajax() instead
htmx.logAll()Set htmx.config.logAll = true
htmx.logNone()Set htmx.config.logAll = false
htmx.loggerUse browser DevTools or custom event listeners
htmx.off()Use native removeEventListener()
htmx.remove()Use native element.remove()
htmx.removeClass()Use native element.classList.remove()
htmx.removeExtension()Extensions are now event-based, no removal needed
htmx.toggleClass()Use native element.classList.toggle()

Retained API Methods

These methods continue to exist in htmx 4:

New API Methods

Extension API Changes

Extensions in htmx 4 use a new event-based hook system instead of the callback-based API. The method name has also changed from defineExtension() to registerExtension() to avoid conflicts with htmx 2.x.

Key changes:

Extensions will almost certainly need a rewrite. Please see our Extensions documentation and Extension Migration Guide for more information.


HTTP Header Changes

htmx 4 makes some changes to the HTTP headers sent with requests and the response headers it processes. If your server-side code relies on htmx headers, you will need to update it.

Changed Request Headers

htmx 2.x Headerhtmx 4.x HeaderNotes
HX-TriggerHX-SourceNow uses element identifier format: tagName#id (e.g., button#submit) instead of just the element’s ID. This is the replacement for HX-Trigger.
HX-TargetHX-TargetStill present but now uses element identifier format: tagName#id instead of just the element’s ID

HX-Source is the direct replacement for HX-Trigger. If your server was using HX-Trigger to identify which element initiated the request, use HX-Source in htmx 4. Note that the format has changed from just an ID to tagName#id.

Removed Request Headers

The following request headers have been removed in htmx 4:

Removed HeaderNotes
HX-Trigger-NamePreviously sent the name attribute of the triggering element. Use HX-Source instead.
HX-PromptPreviously sent the user’s response to hx-prompt. Use hx-confirm with async JavaScript instead (see attribute changes above).

New Request Headers

HeaderDescription
HX-Request-TypeSet to "full" for full page requests (target is body or has hx-select) or "partial" for partial page requests
AcceptNow explicitly set to "text/html, text/event-stream"

Removed Response Headers

The following response headers are no longer processed in htmx 4:

Removed HeaderNotes
HX-Trigger-After-SwapUse HX-Trigger or custom javascript instead. Timing-specific triggers are no longer supported.
HX-Trigger-After-SettleUse HX-Trigger or custom javascript instead. Timing-specific triggers are no longer supported.

Unchanged Response Headers

The following response headers continue to work the same in htmx 4:


Upgrade Music

This is the official htmx 2.x -> 4.x upgrade music: