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.


Real-time collaborative editors, canvas tools, offline-first PWAs, and dashboards with dense local state still need client-side state management. Htmx is a poor fit there. Most internal tools, back-office UIs, and CRUD interfaces have a different state model, yet often become SPAs through habit. Checking where the state lives before choosing the stack avoids that default.

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.

Notes

  • 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.