🎪 HTMX primitive examples
Every demo below is plain HTML plus an HTMX attribute - no hand-written JavaScript. Reload this page to restore any state a demo consumed.
1. HTTP verbs
Five buttons issue five different verbs to one backend route,
/api/examples/verbs. The response echoes which verb arrived.
2. Triggers
hx-trigger decides what starts the request - and how often.
change
keyup changed delay:300ms
Type, then pause. The request fires once you stop, not per keystroke.
click once
This button can fire exactly once - later clicks stay silent (watch the server log).
every 2s (polling)
HTMX asks the backend every two seconds and swaps in a fresh crowd count.
Waiting for the first poll…3. Targets & swap styles
The same endpoint /api/examples/swaps returns one chip. Each button
aims it at a different hx-target using a different hx-swap
style. Reload the page to bring replaced elements back.
hx-target + hx-swap="innerHTML"
hx-swap="outerHTML" (replaces the target element itself)
hx-swap="beforeend" (appends inside the target)
hx-swap="delete" (removes the target element)
hx-target="closest .demo-box"
I am the whole box (the nearest .demo-box to the button).
4. Forms & values
hx-post (submit a form without leaving the page)
hx-include (add a value from a field elsewhere on the page)
hx-vals (attach canned values to the request)
5. Typed search (debounce + hx-indicator)
Type in the box. HTMX waits until you pause, then asks the backend to filter the line-up - a spinner shows while the request is in flight.
6. hx-select
The backend returns a big card, but hx-select="#featured" keeps only
the matching node - the rest of the response is discarded.
7. hx-confirm
hx-confirm asks before the destructive request is sent. The backend
removes an in-memory reservation; state resets when the server restarts.
8. hx-indicator & hx-disabled-elt
A slow endpoint keeps the request running for a moment. The spinner appears via the
htmx-request class, and the button disables itself for the duration.
9. hx-swap-oob (out-of-band swaps)
One response updates the main target and a different spot elsewhere on
the page, because the returned fragment carries
hx-swap-oob="innerHTML".
Meanwhile this note is updated out-of-band: