htmx lets you build modern, interactive web apps using HTML attributes instead of JavaScript frameworks. Its API surface is tiny but incredibly powerful.
Core: AJAX via HTML Attributes
<!-- GET request on click -->
<button hx-get="/api/data" hx-target="#results" hx-swap="innerHTML">
Load Data
</button>
<div id="results"></div>
<!-- POST form without page reload -->
<form hx-post="/api/items" hx-target="#item-list" hx-swap="afterbegin">
<input name="title" placeholder="New item">
<button type="submit">Add</button>
</form>
<!-- DELETE with confirmation -->
<button hx-delete="/api/items/42" hx-confirm="Are you sure?" hx-target="closest tr" hx-swap="outerHTML">
Delete
</button>
Triggers: Any Event
<!-- Search on keyup with debounce -->
<input type="search" name="q"
hx-get="/api/search"
hx-trigger="keyup changed delay:300ms"
hx-target="#results"
hx-indicator="#spinner">
<!-- Load on scroll (infinite scroll) -->
<div hx-get="/api/items?page=2"
hx-trigger="revealed"
hx-swap="afterend">
Loading...
</div>
<!-- Poll every 5 seconds -->
<div hx-get="/api/status"
hx-trigger="every 5s"
hx-swap="innerHTML">
</div>
<!-- Intersection observer -->
<img hx-get="/api/image/lazy" hx-trigger="intersect once" hx-swap="outerHTML">
Swap Strategies
<!-- Replace inner content -->
<div hx-get="/data" hx-swap="innerHTML">old content</div>
<!-- Replace entire element -->
<div hx-get="/data" hx-swap="outerHTML">replaces this div</div>
<!-- Append/Prepend -->
<ul hx-get="/items" hx-swap="afterbegin">new items go first</ul>
<!-- Out-of-band swaps (update multiple elements) -->
<!-- Server response: -->
<div id="notification" hx-swap-oob="true">New notification!</div>
<tr>...main response row...</tr>
CSS Transitions
<style>
.htmx-swapping { opacity: 0; transition: opacity 0.5s; }
.htmx-settling { opacity: 1; transition: opacity 0.5s; }
.htmx-added { opacity: 0; }
</style>
<div hx-get="/content" hx-swap="innerHTML swap:500ms settle:500ms">
Content fades out, new content fades in
</div>
Extensions
<!-- Server-Sent Events -->
<div hx-ext="sse" sse-connect="/api/events" sse-swap="message">
Live updates appear here
</div>
<!-- WebSocket -->
<div hx-ext="ws" ws-connect="/chat">
<form ws-send>
<input name="message">
<button>Send</button>
</form>
<div id="messages"></div>
</div>
<!-- JSON encoding -->
<form hx-ext="json-enc" hx-post="/api/data">
Sends JSON instead of form-encoded
</form>
htmx Events API
document.body.addEventListener("htmx:afterSwap", (e) => {
console.log("Swapped:", e.detail.target);
});
document.body.addEventListener("htmx:beforeRequest", (e) => {
e.detail.headers["X-Custom-Header"] = "value";
});
document.body.addEventListener("htmx:responseError", (e) => {
showToast("Request failed: " + e.detail.xhr.status);
});
Build server-rendered data apps? My Apify tools deliver data for your htmx-powered server.
Custom solution? Email spinov001@gmail.com
Top comments (0)