htmx swap silently does nothing when the target element is removed before the response arrives
0 reputation · 26 Feb 2024, 01:06 UTC
0 reputation · 26 Feb 2024, 01:06 UTC
I am building a page where an htmx request targets a container that can be re-rendered by a separate part of the UI while the request is still in flight. The button uses hx-get with hx-target pointing at that container and hx-swap="innerHTML". When the container is replaced in the DOM before the response returns, the update appears to vanish: no visible change, and no error surfaced in the console.
My understanding is that htmx resolves the target at request time, and if that node is detached before the swap runs, the mutation is applied to a detached element and effectively lost. I also see references to rapid sequential requests against the same target producing last-response-wins behavior, which may overlap with what I am seeing when the container is re-created between requests.
Assume htmx 1.9.x loaded from the official CDN, standard browser behavior, and a server returning a plain HTML fragment with a 200 status.
Is the silent no-op when the target is detached the documented, expected behavior, or should htmx report it somewhere? Does re-resolving the selector at swap time versus request time change anything here? And what is the intended pattern for guaranteeing a swap lands when the target region can be re-rendered concurrently?
30775 reputation · 26 Feb 2024, 04:28 UTC
In htmx 1.9.x the target element is looked up when the request is started and that DOM node is stored. If the node is removed from the document before the response returns, htmx still performs the swap on that detached node, so the new HTML is never visible and no error is logged by default. This silent no‑op is the current expected behavior, not a bug.
Because the second case can silently inject outdated content, htmx deliberately resolves the target once at request time.
hx-target at that wrapper and swap only its inner content (e.g., innerHTML).<div id="stable">
<div id="volatile"></div>
</div>
<button hx-get="/fragment"
hx-target="#stable"
hx-swap="innerHTML">Load</button>Add hx-sync on a common ancestor (e.g., hx-sync="this:replace") to cancel earlier requests, giving deterministic last‑request‑wins behavior. This only coordinates htmx‑issued swaps; it does not protect against external DOM replacement, so the stable wrapper is still required.
Are the concurrent re‑renders of the container performed by htmx itself (another request or out‑of‑band swap) or by external code (React, Vue, manual innerHTML)? If they are htmx‑driven, hx-sync or OOB swaps can coordinate everything inside htmx; if they are external, the stable‑wrapper pattern is the only robust fix.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.