HTMX lets any HTML element make HTTP requests and swap content — no JavaScript needed. Build dynamic web apps with just HTML attributes.
Core Attributes
<!-- Click to load content -->
<button hx-get="/api/users" hx-target="#user-list" hx-swap="innerHTML">
Load Users
</button>
<div id="user-list"></div>
<!-- Form that submits via AJAX -->
<form hx-post="/api/users" hx-target="#result" hx-swap="afterbegin">
<input name="name" placeholder="Name">
<input name="email" placeholder="Email">
<button type="submit">Create User</button>
</form>
<div id="result"></div>
<!-- Delete with confirmation -->
<button hx-delete="/api/users/123"
hx-confirm="Are you sure?"
hx-target="closest tr"
hx-swap="outerHTML">
Delete
</button>
Server-Sent Events
<!-- Real-time updates -->
<div hx-ext="sse" sse-connect="/api/notifications">
<div sse-swap="message"></div>
</div>
Infinite Scroll
<table>
<tbody id="rows" hx-get="/api/rows?page=1"
hx-trigger="load"
hx-swap="innerHTML">
</tbody>
</table>
<!-- Server returns rows + trigger for next page -->
<!-- Each last row has: hx-get="/api/rows?page=2" hx-trigger="revealed" hx-swap="afterend" -->
Active Search
<input type="search"
name="q"
hx-get="/api/search"
hx-trigger="input changed delay:300ms"
hx-target="#search-results">
<div id="search-results"></div>
Server Side (Express Example)
app.get('/api/users', (req, res) => {
const users = db.getUsers();
// Return HTML fragments, not JSON
res.send(users.map(u =>
`<tr>
<td>${u.name}</td>
<td>${u.email}</td>
<td><button hx-delete="/api/users/${u.id}" hx-target="closest tr" hx-swap="outerHTML">Delete</button></td>
</tr>`
).join(''));
});
Why This Matters
- No build step: Just add a script tag
- Server-rendered: SEO friendly by default
- Progressive enhancement: Works without JS, better with it
- 10KB: vs 100KB+ for React/Vue/Angular
Need custom web tools or frontend automation? I build developer tools. Check out my web scraping actors on Apify or reach out at spinov001@gmail.com for custom solutions.
Top comments (0)