htmx 4 behavior reference
This page documents the htmx 4 request/response contract that htmx.NET implements: the request and response headers, status-code behavior, config keys, events, and swap styles. It draws on the official htmx 4 docs and the v4.0.0 release source.
1. Request headers
Section titled “1. Request headers”| Header | v4 status and format | Notes |
|---|---|---|
HX-Request |
Present. Always true on core htmx requests. |
Indicates that htmx made the request. HX-Request reference |
HX-Source |
Present; replaces request-side HX-Trigger. Format is <tag>#<id>, or just <tag> when the source has no ID; it is not empty in that case. The tag is lowercase in the v4.0.0 implementation, and IDs are URI-encoded. |
Examples: button#submit; div. The release source builds this value from tagName.toLowerCase() and appends the encoded ID only when present. HX-Source reference · v4.0.0 source · Upgrade guide |
HX-Target |
Present only when a target is specified. Format is <tag>#<id>, or just <tag> for a target without an ID. The tag is lowercase in the v4.0.0 implementation. |
This is an element identifier, not the old bare-ID-only format. HX-Target reference · v4.0.0 source |
HX-Request-Type |
New in v4. Exact values are full and partial. |
full is sent when the target is body or hx-select is used. partial is sent for another target, including the default source-element target. The value is calculated from the final target/selection before the request is sent. HX-Request-Type reference · v4.0.0 source |
HX-Trigger-Name |
Removed. | The upgrade guide says to use HX-Source instead. Upgrade guide |
HX-Boosted |
Present when applicable; value true. |
Sent when the request comes from a link or form enhanced by hx-boost. HX-Boosted reference |
HX-Current-URL |
Present. Contains the browser URL when the request was made. | Example format: https://example.com/products. HX-Current-URL reference |
HX-History-Restore-Request |
Present when applicable; value true. |
Sent when the user navigates back or forward in history. In v4, history restoration re-fetches from the server by default rather than restoring from the former built-in localStorage cache. HX-History-Restore-Request reference · Upgrade guide |
HX-Prompt |
Not sent by core. Available through the hx-prompt extension. |
The extension sends the user’s answer in this header; canceling the prompt prevents the request. hx-prompt extension · Upgrade guide |
Accept |
New core request header. Core requests send text/html. |
The upgrade guide notes that the hx-sse extension adds text/event-stream. Upgrade guide |
The v4 reference’s request-header section lists HX-Request, HX-Request-Type, HX-Current-URL, HX-Source, HX-Target, HX-Boosted, and HX-History-Restore-Request as the core request headers. Request-header reference index
2. Response headers
Section titled “2. Response headers”| Header | v4 status and semantics |
|---|---|
HX-Trigger |
Supported. Triggers client-side events after the swap completes. See the JSON detail format below. HX-Trigger reference |
HX-Trigger-After-Swap |
Removed. v4 consolidates the old trigger headers into HX-Trigger. Upgrade guide |
HX-Trigger-After-Settle |
Removed. v4 consolidates the old trigger headers into HX-Trigger. Upgrade guide |
HX-Push-Url |
Supported. Pushes a URL into browser history; false prevents a history update. HX-Push-Url reference |
HX-Replace-Url |
Supported. Replaces the current history URL without adding a history entry; false prevents a URL update. HX-Replace-Url reference |
HX-Redirect |
Supported. Performs a full browser navigation by setting location.href. HX-Redirect reference |
HX-Location |
Supported. Starts htmx navigation without a full page load. HX-Location reference |
HX-Refresh |
Supported. When true, reloads the full page. HX-Refresh reference |
HX-Retarget |
Supported. Overrides the response target with a CSS selector. HX-Retarget reference |
HX-Reswap |
Supported. Overrides the swap style; accepts the same values as hx-swap, including modifiers. HX-Reswap reference |
HX-Reselect |
Supported. Overrides the CSS selector used to select content from the response. HX-Reselect reference |
Response headers are not processed on 3xx responses; use a 2xx response when relying on these htmx headers. HX-Trigger reference · HX-Location reference
HX-Location JSON keys
Section titled “HX-Location JSON keys”HX-Location can be a path string or JSON. The JSON must include path. The documented htmx.ajax option fields are source, event, target, swap, select, selectOOB, transition, values, and headers. The HX-Location page permits serializable htmx.ajax options; the htmx.ajax reference documents those fields. handler is not listed as a supported option. HX-Location reference · htmx.ajax reference
| JSON key | Documented? |
|---|---|
path |
Yes; required for the object form. HX-Location reference |
target, swap, select, values, headers |
Yes. HX-Location reference · htmx.ajax options |
source, event, selectOOB, transition |
Listed htmx.ajax options, hence within the HX-Location page’s “serializable options” description. HX-Location reference · htmx.ajax options |
handler |
Not listed among documented htmx.ajax options. htmx.ajax options |
The documentation does not define whether every listed htmx.ajax option is meaningful when serialized into an HTTP header (notably event). Treat those fields as “documented options,” not as a guarantee that every JSON value form is useful.
HX-Trigger JSON detail
Section titled “HX-Trigger JSON detail”v4 documents event names as top-level JSON keys. A scalar value is exposed as event.detail.value; an object value has its properties copied onto the event detail; an object can include target to dispatch on another element. The upgrade guide labels the header unchanged, and the v4 reference describes these JSON-detail forms. HX-Trigger reference · Upgrade guide
3. Status-code behavior and polling
Section titled “3. Status-code behavior and polling”| Question | v4 fact |
|---|---|
Does status 286 still stop polling? |
The official v4 upgrade guide does not document 286 as a polling stop signal. The v4.0.0 source’s every trigger uses a timer that continues firing while its element remains connected; it does not contain a 286 stop branch. Polling documentation · v4.0.0 source |
What replaces 286? |
There is no documented status-code replacement in the official v4 docs. The documented load-polling pattern continues by having each response replace the polling element with another element configured to poll; stop by returning content that does not contain the poller. For an every trigger, the source timer continues while the trigger element remains connected, so the docs do not establish an equivalent status-based stop mechanism. Load polling documentation · v4.0.0 source |
| Which statuses do not swap by default? | The default htmx.config.noSwap is [204, 304]. noSwap is configurable. noSwap config reference |
| Do 4xx/5xx responses swap by default? | Yes. v4 swaps all responses by default except configured noSwap statuses; the default exclusions are 204 and 304. Use hx-status or noSwap to change behavior. hx-status reference · Upgrade guide |
4. Configuration
Section titled “4. Configuration”The official htmx.config reference provides the complete available-options list below. Types are the JSON/JavaScript types implied by the documented defaults; undefined means the reference does not provide a concrete default value. htmx.config reference
| v4 key | Type and default | Source |
|---|---|---|
logAll |
boolean; false |
config reference |
prefix |
string; "data-hx-" |
config reference · prefix reference |
metaCharacter |
string or undefined; undefined (uses :) |
config reference · metaCharacter reference |
transitions |
boolean; false |
config reference |
history |
boolean or string mode; true |
config reference |
mode |
string; "same-origin" |
config reference · mode reference |
defaultSwap |
string; "innerHTML" |
config reference |
allowEmptySwapAfterOOB |
boolean; false |
config reference |
defaultFocusScroll |
boolean; false |
config reference |
defaultSettleDelay |
number (milliseconds); 1 |
config reference · defaultSettleDelay reference |
indicatorClass |
string; "htmx-indicator" |
config reference · indicatorClass reference |
requestClass |
string; "htmx-request" |
config reference · requestClass reference |
includeIndicatorCSS |
boolean; true |
config reference |
defaultTimeout |
number (milliseconds); 60000 |
config reference · defaultTimeout reference |
extensions |
string; "" |
config reference |
morphIgnore |
array of strings; ["data-htmx-powered"] |
config reference |
morphSkip |
string (CSS selector); "[hx-morph-skip]" |
config reference |
morphSkipChildren |
string (CSS selector); "[hx-morph-skip-children]" |
config reference |
morphScanLimit |
number; 10 |
config reference |
noSwap |
array of numbers and/or status-pattern strings; [204, 304] |
config reference · noSwap reference |
implicitInheritance |
boolean; false |
config reference |
inlineScriptNonce |
string or undefined; undefined |
config reference · inlineScriptNonce reference |
Renames and requested legacy keys
Section titled “Renames and requested legacy keys”| htmx 2 name or candidate | v4 finding |
|---|---|
defaultSwapStyle |
Renamed to defaultSwap. Upgrade guide |
globalViewTransitions |
Renamed to transitions. Upgrade guide |
historyEnabled |
Renamed to history. Upgrade guide |
includeIndicatorStyles |
Renamed to includeIndicatorCSS. Upgrade guide |
timeout |
Renamed to defaultTimeout; v4 default is 60000 ms. Upgrade guide · defaultTimeout reference |
implicitInheritance |
New v4 config key; default false. htmx.config reference |
noSwap |
v4 config key; default [204, 304]. noSwap reference |
prefix |
v4 config key; default "data-hx-". It is additive to the always-recognized hx- prefix; setting a custom value replaces the secondary data-hx- prefix. prefix reference |
extensions |
v4 config key; default "". htmx.config reference |
allowEmptySwapAfterOOB |
v4 config key; default false. htmx.config reference |
allowEmptySwap |
Not a listed v4 config key. The relevant config name is allowEmptySwapAfterOOB; swapEmpty is an hx-swap modifier. htmx.config reference · swap options |
indicatorClass, requestClass |
Survive as config keys. htmx.config reference |
inlineScriptNonce |
Survives as a config key. inlineScriptNonce reference |
inlineStyleNonce |
Removed; the upgrade guide says indicator CSS now uses Constructable Stylesheets, so an inline-style nonce is no longer needed. Upgrade guide |
defaultSettleDelay |
Survives; default changed from 20 ms to 1 ms. Upgrade guide |
defaultFocusScroll |
Present in the v4 config reference. htmx.config reference |
reportValidityOfForms |
Not listed in the v4 config reference or v4 migration config table. Its status as a prior-version setting is not clarified there. htmx.config reference · Upgrade guide |
historyRestoreAsHxRequest |
Not listed in the v4 config reference or v4 migration config table. htmx.config reference · Upgrade guide |
The v4 upgrade guide explicitly lists the following as removed with no v4 config equivalent: refreshOnHistoryMiss, historyCacheSize, defaultSwapDelay, addedClass, settlingClass, swappingClass, allowEval, allowScriptTags, attributesToSettle, useTemplateFragments, wsReconnectDelay, wsBinaryType, disableSelector, withCredentials, scrollBehavior, getCacheBusterParam, methodsThatUseUrlParams, selfRequestsOnly, ignoreTitle, scrollIntoViewOnBoost, triggerSpecsCache, allowNestedOobSwaps, and responseHandling. The guide notes disableSelector is replaced by hx-ignore, selfRequestsOnly by htmx.config.mode, withCredentials by hx-config, and responseHandling by hx-status with noSwap; ignoreTitle remains available as an hx-swap option. Upgrade guide: config
5. Events and event detail
Section titled “5. Events and event detail”Request configuration and CSRF
Section titled “Request configuration and CSRF”The exact event name is htmx:config:request. It fires after values are collected and validated but before request data is encoded and sent. Its evt.detail.ctx.request object exposes method, action, headers, and body, among other request properties. method is the HTTP method string (for example, "GET" or "POST"). At this event, body is a FormData object when applicable, so .set(name, value) is the documented way to add/update a body field. GET and DELETE requests have a null body before encoding; use the method to distinguish them, or add CSRF data as a request header. config:request reference · Events guide: ctx.request · Events guide: adding a value to every request
htmx.on('htmx:config:request', (evt) => { const request = evt.detail.ctx.request;
if (request.method !== 'GET' && request.method !== 'DELETE' && request.body) { request.body.set('csrf-token', getToken()); }
// Alternatively, send the token as a header for all methods: request.headers['X-CSRF-Token'] = getToken();});The example is an implementation pattern based on the documented event API, not a prescribed ASP.NET Core antiforgery convention. Events guide: adding a value to every request
Post-response content
Section titled “Post-response content”The event is htmx:after:request. It fires after the response body has been read and before swapping. Response status is at evt.detail.ctx.response.status; the response text is at evt.detail.ctx.text. ctx.response contains the raw Fetch Response, status, and headers; it is not where the guide documents the text string. after:request reference · Events guide: ctx object
Former htmx:afterOnLoad
Section titled “Former htmx:afterOnLoad”The upgrade guide maps htmx:afterOnLoad → htmx:after:init. In the v4 reference, htmx:after:init fires after an element is fully initialized; it is not described as an event specifically for boosted navigation completion. For a swap-completion hook, the v4 lifecycle includes htmx:after:swap and htmx:after:settle. Upgrade guide: events · after:init reference · Events guide: request/swap lifecycle
6. Attribute model and empty hx-get
Section titled “6. Attribute model and empty hx-get”- Attribute inheritance is explicit by default in v4. Use the
:inheritedmodifier, for examplehx-target:inherited="#result". Upgrade guide: explicit inheritance · Attribute inheritance documentation hx-disinheritandhx-inheritare removed; the upgrade guide says they are no longer needed with explicit inheritance. Upgrade guide: attribute removalsprefixdefaults to"data-hx-". The secondary prefix works alongsidehx-; if a custom prefix is set, it replaces the secondary prefix. prefix reference- An empty
hx-getvalue is valid: it requests the current URL and swaps the current HTML page. hx-get reference
7. Swap styles
Section titled “7. Swap styles”The v4 docs list these valid swap styles and aliases:
| v4 token | Meaning / alias |
|---|---|
innerHTML |
Default; inserts response content inside the target. |
outerHTML |
Replaces the target element. |
outerSync |
Morphs target attributes, then replaces its children while retaining the target. |
before / beforebegin |
Insert before the target in its parent. |
prepend / afterbegin |
Insert before the target’s first child. |
append / beforeend |
Insert after the target’s last child. |
after / afterend |
Insert after the target in its parent. |
delete |
Remove the target. |
none |
Do not append response content; OOB swaps and response headers are still processed. |
innerMorph |
Morph the target’s children. |
outerMorph |
Morph the target itself. |
textContent |
Set target text without parsing HTML. |
All tokens and descriptions above are documented in the v4 swap-style table. Swap styles documentation · What’s New: swap styles
8. <hx-partial> and OOB ordering
Section titled “8. <hx-partial> and OOB ordering”<hx-partial> wraps response content and directs it to a target with its own optional swap strategy. It can use hx-target or id as the target shorthand; the default swap is innerHTML. For a response containing only partials, the main target is left untouched. <hx-partial> reference
In v4, the main content swap occurs first, then OOB and <hx-partial> swaps occur afterward in document order. This reverses the v2 OOB-before-main ordering. Upgrade guide: OOB swap order
9. Vary and caching
Section titled “9. Vary and caching”The v4 caching guidance says to use Vary: HX-Request when the same URL returns a full page for non-htmx requests and a fragment for HX-Request: true. It also states the general rule: if a response varies based on other request headers, include those headers in Vary. Caching documentation
HX-Request-Type is the v4 header that distinguishes full from partial requests. The v4 caching example does not explicitly mention it. Therefore, if an application varies its representation specifically by HX-Request-Type, including HX-Request-Type in Vary follows the documented general rule; this is an inference from the two docs, not an explicit v4 caching recommendation. HX-Request-Type reference · Caching documentation
Ambiguities and how htmx.NET resolves them
Section titled “Ambiguities and how htmx.NET resolves them”A few areas of the htmx 4 docs are underspecified. This is how htmx.NET interprets each one.
- Polling stop signal: the official v4 docs do not state whether any replacement status code exists for v2’s
286. The v4.0.0 source showseverytimers continue while their element remains connected; the documented load-polling pattern instead continues by returning a replacement poller. htmx.NET therefore marksStopPolling()(which set status 286) as[Obsolete(error: true)]— stop polling by returning content that no longer contains the polling element. - Caching on
HX-Request-Type: the caching section’s specific example mentions onlyHX-Request; it does not explicitly discussHX-Request-Type. The generalVaryrule implies varying onHX-Request-Typewhen representations depend on it. HX-Locationserialization ofevent: the docs listeventas an htmx.ajax option and say HX-Location accepts serializable htmx.ajax options, but do not explain what serialized event value is useful or accepted.handleris not listed, so htmx.NET removedHtmxLocation.Handler.reportValidityOfFormsandhistoryRestoreAsHxRequest: neither appears in the complete v4 config list or the upgrade guide’s removed-config list, so the docs do not clearly state whether these were prior-version config keys that were intentionally removed or simply unsupported names. htmx.NET does not expose either on the config tag helper.HX-Triggerequivalence: the upgrade guide calls the header unchanged, while the v4 reference documents its JSON behavior. htmx.NET’sWithTriggerpreserves the v4-documentedvalue, copied-object-properties, andtargetbehavior.