Server-Driven UI with htmx
title: "Server-Driven UI with htmx" slug: "web-htmx-server-driven-ui" description: "Build interactive web apps with htmx: HTML-over-the-wire, hx-get and hx-post attributes, partial page updates, and when server-driven UI beats SPA complexity." datePublished: "2026-05-05" dateModified: "2026-07-17" tags:
- "Engineering" keywords: "htmx, server-driven UI, HTML over the wire, partial updates, hypermedia, hx-get, hx-swap" faq:
- q: "What is the main production risk with web htmx server driven ui?" a: "Teams ship without field measurement—web htmx server driven ui failures appear as silent UX regressions, cost drift, or audit findings rather than clear errors."
- q: "When should we prioritize web htmx server driven ui?" a: "Prioritize when user research, CrUX, support tickets, or compliance requirements show pain on critical paths—not when a checklist mentions it abstractly."
- q: "How do we validate web htmx server driven ui changes?" a: "Baseline RUM before changes, compare p75 after deploy, and keep rollback via feature flags or cache purge documented in the PR."
title: "web-htmx-server-driven-ui" slug: "web-htmx-server-driven-ui" description: "" datePublished: "2026-07-17" dateModified: "2026-07-17" tags:
- "Engineering" keywords: "web-htmx-server-driven-ui" faq:
- q: "What is the main production risk with web htmx server driven ui?" a: "Teams ship without field measurement—web htmx server driven ui failures appear as silent UX regressions, cost drift, or audit findings rather than clear errors."
- q: "When should we prioritize web htmx server driven ui?" a: "Prioritize when user research, CrUX, support tickets, or compliance requirements show pain on critical paths—not when a checklist mentions it abstractly."
- q: "How do we validate web htmx server driven ui changes?" a: "Baseline RUM before changes, compare p75 after deploy, and keep rollback via feature flags or cache purge documented in the PR."
title: "web-htmx-server-driven-ui" slug: "web-htmx-server-driven-ui" description: "" datePublished: "2026-07-17" dateModified: "2026-07-17" tags:
- "Engineering" keywords: "web-htmx-server-driven-ui" faq:
- q: "What is the main production risk with web htmx server driven ui?" a: "Teams ship without field measurement—web htmx server driven ui failures appear as silent UX regressions, cost drift, or audit findings rather than clear errors."
- q: "When should we prioritize web htmx server driven ui?" a: "Prioritize when user research, CrUX, support tickets, or compliance requirements show pain on critical paths—not when a checklist mentions it abstractly."
- q: "How do we validate web htmx server driven ui changes?" a: "Baseline RUM before changes, compare p75 after deploy, and keep rollback via feature flags or cache purge documented in the PR."
title: "web-htmx-server-driven-ui" slug: "web-htmx-server-driven-ui" description: "" datePublished: "2026-07-17" dateModified: "2026-07-17" tags:
- "Engineering" keywords: "web-htmx-server-driven-ui" faq:
- q: "What is the main production risk with web htmx server driven ui?" a: "Teams ship without field measurement—web htmx server driven ui failures appear as silent UX regressions, cost drift, or audit findings rather than clear errors."
- q: "When should we prioritize web htmx server driven ui?" a: "Prioritize when user research, CrUX, support tickets, or compliance requirements show pain on critical paths—not when a checklist mentions it abstractly."
- q: "How do we validate web htmx server driven ui changes?" a: "Baseline RUM before changes, compare p75 after deploy, and keep rollback via feature flags or cache purge documented in the PR."
title: "web-htmx-server-driven-ui" slug: "web-htmx-server-driven-ui" description: "" datePublished: "2026-07-17" dateModified: "2026-07-17" tags:
- "Engineering" keywords: "web-htmx-server-driven-ui" faq:
- q: "What is the main production risk with web htmx server driven ui?" a: "Teams ship without field measurement—web htmx server driven ui failures appear as silent UX regressions, cost drift, or audit findings rather than clear errors."
- q: "When should we prioritize web htmx server driven ui?" a: "Prioritize when user research, CrUX, support tickets, or compliance requirements show pain on critical paths—not when a checklist mentions it abstractly."
- q: "How do we validate web htmx server driven ui changes?" a: "Baseline RUM before changes, compare p75 after deploy, and keep rollback via feature flags or cache purge documented in the PR."
title: "web-htmx-server-driven-ui" slug: "web-htmx-server-driven-ui" description: "" datePublished: "2026-07-17" dateModified: "2026-07-17" tags:
- "Engineering" keywords: "web-htmx-server-driven-ui" faq:
- q: "What is the main production risk with web htmx server driven ui?" a: "Teams ship without field measurement—web htmx server driven ui failures appear as silent UX regressions, cost drift, or audit findings rather than clear errors."
- q: "When should we prioritize web htmx server driven ui?" a: "Prioritize when user research, CrUX, support tickets, or compliance requirements show pain on critical paths—not when a checklist mentions it abstractly."
- q: "How do we validate web htmx server driven ui changes?" a: "Baseline RUM before changes, compare p75 after deploy, and keep rollback via feature flags or cache purge documented in the PR."
title: "Server-Driven UI with htmx" slug: "web-htmx-server-driven-ui" description: "Build interactive web apps with htmx: HTML-over-the-wire, hx-get and hx-post attributes, partial page updates, and when server-driven UI beats SPA complexity." datePublished: "2026-05-05" dateModified: "2026-07-17" tags:
- "Web"
- "htmx"
- "Backend"
- "Frontend" keywords: "htmx, server-driven UI, HTML over the wire, partial updates, hypermedia, hx-get, hx-swap" faq:
- q: "What is the main production risk with web htmx server driven ui?" a: "Teams ship without field measurement—web htmx server driven ui failures appear as silent UX regressions, cost drift, or audit findings rather than clear errors."
- q: "When should we prioritize web htmx server driven ui?" a: "Prioritize when user research, CrUX, support tickets, or compliance requirements show pain on critical paths—not when a checklist mentions it abstractly."
- q: "How do we validate web htmx server driven ui changes?" a: "Baseline RUM before changes, compare p75 after deploy, and keep rollback via feature flags or cache purge documented in the PR."
Our admin dashboard was a React SPA with 200 API endpoints returning JSON that the client re-rendered into HTML. Adding a filter dropdown required a new API route, a TypeScript type, a React component, and a loading state. We rebuilt one section with htmx: the server returned an HTML table fragment, the client swapped it in. The feature shipped in an afternoon.
Core attributes
<!-- Load content on click -->
<button hx-get="/stats" hx-target="#stats-panel" hx-swap="innerHTML">
Load stats
</button>
<div id="stats-panel"></div>
<!-- Submit form, replace table body -->
<form hx-post="/users/search" hx-target="#user-table" hx-swap="outerHTML">
<input name="q" type="search" placeholder="Search users" />
<button type="submit">Search</button>
</form>
<table id="user-table">...</table>
<!-- Auto-refresh every 30 seconds -->
<div hx-get="/notifications/count" hx-trigger="every 30s" hx-swap="innerHTML">
3 new
</div>
| Attribute | Purpose |
|---|---|
hx-get, hx-post, hx-put, hx-delete |
HTTP method and URL |
hx-target |
CSS selector for swap target |
hx-swap |
How to insert response (innerHTML, outerHTML, beforeend, delete) |
hx-trigger |
Event that fires request (click, submit, every 2s, revealed) |
hx-indicator |
Loading spinner element |
Server-side partial rendering
Detect htmx requests and return fragments:
# Django view
def user_list(request):
users = User.objects.filter(name__icontains=request.GET.get('q', ''))
template = 'users/_table.html' if request.headers.get('HX-Request') else 'users/list.html'
return render(request, template, {'users': users})
<!-- templates/users/_table.html -->
<table id="user-table">
{% for user in users %}
<tr>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
</tr>
{% endfor %}
</table>
Return only the fragment when HX-Request: true is in the request header.
Out-of-band swaps
Update multiple page regions from one response:
<!-- Response includes -->
<div id="cart-count" hx-swap-oob="true">5 items</div>
<div id="cart-items" hx-swap-oob="true">
<!-- updated cart list -->
</div>
The primary swap target gets the main response body. Elements with hx-swap-oob="true" update their matching IDs elsewhere on the page.
Loading and error states
<button
hx-delete="/items/42"
hx-target="#item-42"
hx-swap="outerHTML swap:1s"
hx-confirm="Delete this item?"
hx-indicator="#spinner"
>
Delete
</button>
<span id="spinner" class="htmx-indicator">Deleting...</span>
CSS hides indicators by default:
.htmx-indicator { display: none; }
.htmx-request .htmx-indicator { display: inline; }
.htmx-request.htmx-indicator { display: inline; }
Handle errors with the htmx:responseError event:
document.body.addEventListener('htmx:responseError', (e) => {
const target = e.detail.target;
target.innerHTML = '<p class="error">Something went wrong. Try again.</p>';
});
When to use htmx vs. SPA
| Use htmx | Use SPA framework |
|---|---|
| CRUD admin panels | Real-time collaborative editing |
| Search/filter tables | Complex client-side state |
| Multi-step forms | Offline-first apps |
| Dashboards with periodic refresh | Heavy animation and transitions |
| Internal tools | Public consumer apps with SEO needs |
htmx excels where server rendering already exists and interactivity needs are moderate.
Progressive enhancement
Without JavaScript, forms submit normally and links navigate to full pages. htmx enhances progressively:
<form action="/search" method="get" hx-get="/search" hx-target="#results">
<input name="q" />
<button type="submit">Search</button>
</form>
The action and method attributes provide the fallback behavior.
hx-boost for full-page navigation
Upgrade regular links to AJAX navigation without JavaScript routers:
<body hx-boost="true">
<a href="/about">About</a> <!-- navigates without full reload -->
</body>
The server returns a full HTML document; htmx swaps the body content. Progressive enhancement for multi-page apps.
hx-swap-oob for toasts
Return toast notifications alongside main content:
<div id="toast" hx-swap-oob="true" class="success">Saved!</div>
Update notification areas without targeting them explicitly in hx-target.
Caching partials
Fragment caches keyed by (route, user_segment, page) reduce server render cost:
@cache.memoize(timeout=60)
def render_contact_table(page, tenant_id):
return render_template('_contact_rows.html', ...)
Invalidate on mutation via HX-Trigger calling cache bust endpoint or versioned ETags in HX-Headers.
WebSocket + htmx extension
htmx websockets extension swaps messages into DOM—useful for live dashboards without full SPA. Still sanitize HTML fragments from server; XSS in partial templates is critical severity.
Comparison with Hotwire/Turbo
Rails Turbo Drive similar to htmx philosophy—teams on Rails often use Turbo; htmx fits Python, Go, PHP, Java templates equally. Choose based on server stack, not religious preference.
Practical follow-through (1)
Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.
Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.
Practical follow-through (2)
Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.
Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.
Practical follow-through (3)
Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.
Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.
Practical follow-through (4)
Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.
Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.
Practical follow-through (5)
Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.
Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.
Resources
- htmx documentation
- htmx examples
- Hypermedia Systems (book)
- django-htmx integration
- htmx vs React comparison
CSRF in partials
Include CSRF tokens in every htmx form partial — cookies send automatically on same-origin POST.
Partial template tests
Pytest-render _table.html fragments with fixture data — no browser needed for row logic. One Playwright spec per critical swap path covers integration.
hx-boost navigation
hx-boost="true" on body upgrades link navigation without full reload — server returns full HTML documents; htmx swaps body content for MPA-style speed.
Frequently asked questions
What is the main production risk with web htmx server driven ui?
Teams ship without field measurement—web htmx server driven ui failures appear as silent UX regressions, cost drift, or audit findings rather than clear errors.
When should we prioritize web htmx server driven ui?
Prioritize when user research, CrUX, support tickets, or compliance requirements show pain on critical paths—not when a checklist mentions it abstractly.
How do we validate web htmx server driven ui changes?
Baseline RUM before changes, compare p75 after deploy, and keep rollback via feature flags or cache purge documented in the PR.
Hiring a senior Android / Flutter engineer?
I architect and ship production mobile software — Kotlin, Jetpack Compose, Flutter — for robotics, EV infrastructure, fintech, and real-time systems. Open to remote roles in Europe and the US.
Get in touch →