HTMX is hard, so let's get it right
Positioning of HTMX: simplicity vs real complexity
- Many see HTMX as “back to early web” simplicity: server-rendered HTML, hypermedia, minimal JS, great for backend-focused developers.
- Several commenters argue the marketing around “simplicity” is misleading once you build anything SPA-like or heavily stateful (e.g., multi-step wizards, complex forms, custom inputs).
- The blog post is read as a useful corrective: HTMX works, but not “all sunshine and rainbows,” and some problems are simply hard regardless of tool.
State management and where complexity lives
- A recurring theme: complexity must live somewhere—client or server.
- HTMX pushes more logic and state to the backend: easier to test, monitor, and type-check (e.g., Go+Templ, Rust+Askama), but requires server sessions, URL encodings, or cookies to track multi-step flows and partial data.
- Debate over “all app state in the URL”:
- Pro: bookmarkability, shareable/search URLs, clear, functional-style inputs to pages.
- Con: modern apps have ephemeral UI state (partial forms, scroll, toggles, nested navigation) that’s awkward in URLs.
- Alternatives discussed: server-side session objects, cookies keyed by flow IDs, hidden fields, or just keeping state in a single large client-side form and using JS to show/hide steps.
Comparisons with React/Vue/Svelte and hybrid approaches
- Multiple people report trying HTMX for “simplicity,” then reverting to JSON APIs + React/Vue/Svelte/SvelteKit when complexity appears; they find React tooling (forms, stores, routing) ultimately more straightforward for big apps.
- Others have shipped real products with HTMX and liked:
- Smaller JS footprint, fewer dependencies.
- Staying in one language/codebase, no API duplication.
- But they admit some features took longer than they would have with a SPA.
- Common compromise: MPA + HTMX for CRUDish interactions, and embed a SPA-ish island (React/Vue/Solid/web components) for complex widgets.
HTMX-specific patterns and pain points
- Several commenters note the post’s implementation could be simpler using HTMX features:
- Out-of-band (OOB) swaps (
hx-swap-oob) to update multiple areas (stepper, labels, breadcrumbs). - Selective fragment rendering (e.g., template block fragments).
- Out-of-band (OOB) swaps (
- Others complain the form-state persistence and per-step round-trips look “gnarly” compared to a single client-side form.
- There is disagreement over HTTP semantics:
- Some dislike responding
200 OKfor validation errors (done because HTMX discards 4xx bodies by default). - Others argue it’s a valid pattern if consistently handled with HTMX events or custom hooks.
- Some dislike responding
Adoption, mental models, and appropriate use-cases
- Developers with “old-school” server-templating/AJAX background often find HTMX natural; SPA-only developers sometimes struggle with “HTML over the wire” and hypermedia thinking.
- General convergence:
- HTMX is excellent for smaller, form-heavy, CRUD, or admin-style apps and incremental interactivity.
- For large, highly dynamic, stateful UIs, HTMX can feel like fighting the tool, and SPA frameworks or richer JS solutions may be a better fit.