htmx Cheat Sheet
A reference for htmx attributes like hx-get, hx-trigger, and hx-swap for building dynamic UIs with server-rendered HTML fragments.
Basic Attributes
Issuing requests on load, click, and input events.
<!-- Fetch content and replace this element's contents --><div hx-get="/api/messages" hx-trigger="load"> Loading...</div><button hx-post="/api/like" hx-target="#like-count" hx-swap="innerHTML"> Like</button><input hx-get="/search" hx-trigger="keyup changed delay:300ms" hx-target="#results" />
Swap Strategies
How hx-swap controls where the response HTML is inserted.
<div hx-get="/item" hx-swap="innerHTML">...</div> <!-- default: replace inner content --><div hx-get="/item" hx-swap="outerHTML">...</div> <!-- replace the whole element --><div hx-get="/item" hx-swap="beforeend">...</div> <!-- append inside, at the end --><div hx-get="/item" hx-swap="afterbegin">...</div> <!-- prepend inside, at the start --><div hx-get="/item" hx-swap="none">...</div> <!-- don't swap anything -->
Core Attributes
The attribute vocabulary that drives most htmx interactions.
- hx-get / hx-post / hx-put / hx-delete- issue an AJAX request of that HTTP method to a URL
- hx-trigger- specifies the event that triggers the request (click, load, keyup, revealed, etc.)
- hx-target- CSS selector for the element that receives the swapped response
- hx-swap- how the response HTML is inserted relative to the target
- hx-indicator- CSS selector of an element to show while the request is in flight
- hx-vals / hx-include- add extra parameters to the request, e.g. values from other form fields
- hx-boost- progressively enhances normal <a>/<form> elements to use AJAX instead of full page loads
- hx-swap-oob- marks a piece of the response to be swapped into a different part of the page (out of band)
Forms & Loading Indicators
Submitting a form via AJAX and showing a spinner while it loads.
<form hx-post="/comments" hx-target="#comment-list" hx-swap="afterbegin" hx-indicator="#spinner"> <input name="body" /> <button type="submit">Post</button> <img id="spinner" class="htmx-indicator" src="/spinner.gif" /></form>
Out-of-Band Swaps
Updating multiple, unrelated parts of the page from a single response by marking OOB fragments.
<!-- server response for POST /comments --><div id="comment-list" hx-swap-oob="afterbegin"> <div class="comment">New comment text</div></div><span id="comment-count" hx-swap-oob="true">42</span><!-- the primary hx-target element receives the rest of the response normally; any element whose id matches one already in the DOM and carries hx-swap-oob is swapped into that matching element instead -->
Extensions, Headers & CSRF
Loading the SSE extension and attaching custom headers such as a CSRF token to every request.
<script src="https://unpkg.com/htmx.org/dist/ext/sse.js"></script><div hx-ext="sse" sse-connect="/events" sse-swap="message"></div><body hx-headers='{"X-CSRF-Token": "abc123"}'> <!-- every htmx request under this element includes the header --></body><script> document.body.addEventListener('htmx:configRequest', (evt) => { evt.detail.headers['X-CSRF-Token'] = document.querySelector('meta[name=csrf]').content })</script>
Lifecycle Events & Error Handling
Hooking into the request lifecycle to show toasts on error and cancel stale in-flight requests.
document.body.addEventListener('htmx:responseError', (evt) => { const status = evt.detail.xhr.status showToast(`Request failed: ${status}`)})document.body.addEventListener('htmx:beforeSwap', (evt) => { // treat 422 as a valid swap target so validation errors render inline if (evt.detail.xhr.status === 422) evt.detail.shouldSwap = true})document.body.addEventListener('htmx:beforeRequest', (evt) => { if (evt.detail.elt.dataset.cancelPrevious) htmx.trigger(evt.detail.elt, 'htmx:abort')})
History Snapshots & hx-push-url
Making htmx-driven navigation participate correctly in browser back/forward and page restore.
<a href="/articles/42" hx-get="/articles/42" hx-target="#main" hx-push-url="true"> Read article</a><!-- restores from htmx's localStorage history cache on back/forward instead of re-requesting the server, unless hx-history="false" opts an element out --><div hx-history="false">Sensitive content, never cached in history</div>
Request Control & Synchronization
Attributes for taming concurrent requests, retries, and multi-step interactions.
- hx-sync- coordinates requests between elements, e.g. hx-sync="closest form:abort" cancels a stale submit
- hx-trigger="...throttle:1s"- rate-limits how often a trigger can fire a new request
- hx-confirm- shows a native confirm() dialog before issuing the request
- hx-disabled-elt- disables the given selector's elements while the request is in flight
- hx-select / hx-select-oob- extracts a subset of the response by CSS selector before swapping, ignoring the rest
- hx-preserve- keeps an element's DOM node and state (e.g. a video's playback) untouched across swaps
- hx-params- filters which form parameters are included in the request (none, *, or a name list)
The server must respond with HTML fragments, not JSON -- htmx swaps whatever HTML comes back directly into the DOM, so design backend endpoints to render partial templates for each interaction rather than a JSON API.