htmx lets you build modern interactive web applications using HTML attributes instead of JavaScript. It adds AJAX requests, CSS transitions, WebSockets, and Server-Sent Events directly in HTML.
Why htmx Matters
React, Vue, and Svelte require complex JavaScript build toolchains. htmx gives you the same interactivity with zero JavaScript — just HTML attributes.
What you get for free:
- AJAX requests from any HTML element
- Partial page updates (swap HTML fragments)
- CSS transitions and animations
- WebSocket and SSE support
- Form validation and error handling
- History management (back/forward)
- 14KB gzipped, zero dependencies
Quick Start
<script src="https://unpkg.com/htmx.org@2.0.0"></script>
<!-- Click button, load content into div -->
<button hx-get="/api/users" hx-target="#user-list" hx-swap="innerHTML">
Load Users
</button>
<div id="user-list"></div>
<!-- Submit form without page reload -->
<form hx-post="/api/users" hx-target="#result" hx-swap="innerHTML">
<input name="name" placeholder="Name" required />
<input name="email" type="email" placeholder="Email" required />
<button type="submit">Create User</button>
</form>
<div id="result"></div>
Common Patterns
<!-- Delete with confirmation -->
<button hx-delete="/api/users/123"
hx-confirm="Delete this user?"
hx-target="closest tr"
hx-swap="outerHTML swap:0.5s">
Delete
</button>
<!-- Infinite scroll -->
<div hx-get="/api/posts?page=2"
hx-trigger="revealed"
hx-swap="afterend">
Loading more...
</div>
<!-- Search with debounce -->
<input type="search"
name="q"
hx-get="/api/search"
hx-trigger="keyup changed delay:300ms"
hx-target="#results" />
<div id="results"></div>
<!-- Active search indicator -->
<input hx-get="/api/search"
hx-trigger="keyup changed delay:300ms"
hx-indicator="#spinner" />
<span id="spinner" class="htmx-indicator">Searching...</span>
Server-Sent Events
<div hx-ext="sse" sse-connect="/api/events">
<div sse-swap="notification">
<!-- New notifications appear here in real-time -->
</div>
<div sse-swap="score-update">
<!-- Live score updates -->
</div>
</div>
WebSockets
<div hx-ext="ws" ws-connect="/chat">
<div id="messages"></div>
<form ws-send>
<input name="message" />
<button>Send</button>
</form>
</div>
Backend (any language works)
# Flask example — just return HTML fragments
from flask import Flask, render_template_string
app = Flask(__name__)
@app.route("/api/users")
def get_users():
users = db.query(User).all()
return render_template_string("""
{% for user in users %}
<tr>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
<td>
<button hx-delete="/api/users/{{ user.id }}"
hx-target="closest tr"
hx-swap="outerHTML">Delete</button>
</td>
</tr>
{% endfor %}
""", users=users)
Links
Building interactive web apps? Check out my developer tools on Apify or email spinov001@gmail.com for custom solutions.
Top comments (0)