The hx-preserve attribute keeps an element unchanged when an ancestor is replaced.

Preserved elements match by id. Use a stable id, and include the same id in the response.

Response element type and other attributes are ignored.

Syntax

<div id="video-player" hx-preserve="true">...</div>

Notes

  • You can use hx-preserve="true" or use it as a boolean attribute with just hx-preserve
  • Some elements cannot unfortunately be preserved properly, such as <input type="text"> (focus and caret position are lost), iframes or certain types of videos. To tackle some of these cases we recommend the morphdom extension, which does a more elaborate DOM reconciliation
  • When using History Support for actions like the back button hx-preserve elements will also have their state preserved
  • Avoid using hx-swap set to none with requests that could contain a hx-preserve element to avoid losing it
  • hx-preserve can cause elements to be removed from their current location and relocated to a new location when swapping in a partial/oob response
    <div id="new_location"> Just relocated the video here <div id="video" hx-preserve></div> </div>
  • Can be used on the inside content of a hx-swap-oob element
    <div id="notify" hx-swap-oob="true"> Notification updated but keep the same retain <div id="retain" hx-preserve></div> </div>
  • Works with morph swaps (innerMorph/outerMorph). When the server response includes an element with hx-preserve, htmx stashes the live element before morphing and restores it afterward. The id is required for morph the same as for other swap styles. Note that morph already natively preserves element identity for elements with matching ids. DOM state, focus, and scroll position are maintained without hx-preserve. To prevent server updates from changing an element or its children entirely, use hx-morph-skip or hx-morph-skip-children in your server templates. These work similarly to hx-preserve but are morph-specific and don’t always require an id.