Interactions as HTTP: What htmx Gets Right
Interactions as HTTP: What htmx Gets Right
Once you work with htmx, a pattern becomes obvious: most interactions don’t actually need client-side state. They only feel like they do because reaching for a full SPA stack has become the default reflex.
htmx 2.0 shipped in mid-2024, but the core idea hasn’t moved since day one. HTML attributes drive HTTP requests. The server returns an HTML fragment. The browser swaps it into the DOM. No JSON contract, no state store, no serialisation layer on either end. The interaction model is just request/response — the same as the web in the nineties, minus the full-page reload.
<!-- Click the button, GET /tasks, inject the response into #task-list -->
<button hx-get="/tasks" hx-target="#task-list" hx-swap="innerHTML">
Refresh
</button>
<!-- Submit the form, POST /tasks, server returns the updated list fragment -->
<form hx-post="/tasks" hx-target="#task-list" hx-swap="outerHTML">
<input name="title" />
<button type="submit">Add</button>
</form>
The server just needs to return a partial HTML response — no dedicated API layer required:
<!-- This is all the server needs to return -->
<ul id="task-list">
<li>Tidy the docs</li>
<li>Write the tests</li>
</ul>
This fits CRUD dashboards, form-heavy workflows, and admin interfaces well, because their state genuinely belongs in the database rather than in browser memory. There’s no client-server sync problem because you’re always asking the server for the current HTML directly.
That said, not everything belongs here. Real-time collaborative editors, canvas tools, offline-first PWAs, dashboards with dense local state — those still need proper client-side state management, and forcing htmx into those contexts will hurt. The point isn’t that SPAs are wrong. They’re the right tool in the right context. The question worth asking first is: does this actually need to be a SPA? For most internal tools, backoffice UIs, and CRUD interfaces, the honest answer is no. The SPA just arrived by habit.
htmx shifts the default back toward server-driven: render on the server, transport via HTTP, HTML as the payload, and only pull in JS where the interaction genuinely demands it. That’s the hypermedia model the web was built on; htmx just makes it practical to reach for again.
Key Takeaways
- The htmx model:
hx-*attributes trigger HTTP requests, the server returns HTML fragments, the browser patches the DOM, and state stays on the server. - Best fit: CRUD backends, multi-step forms, workflow-heavy admin UIs. Poor fit: real-time collaborative tools, offline-first apps, anything with heavy local state.
- Not an argument against SPAs — an argument for resetting the default, and choosing a SPA only when the requirements justify it.
- The server needs no special API layer; returning partial HTML is enough.
- Tool worship pushes every problem toward SPA. Interrogate the requirements first.
Sheng’s take, drafted with Claude · part of the 2026-06-13 blog renovation, paint still drying.