We made a lot of progress with htmx, but eventually hit a complexity wall where we were spending more time fighting the tool than solving the business need. Note, I'm not blaming htmx here, the documentation is clear about its strengths and limitations, and the hypermedia approach is still fundamentally right. But even with alpinejs in the mix, we just weren't able to achieve the smooth developer experience we were looking for.
So we tried datastar, and it basically addressed all the friction points we had:
- No more DOM hunting to figure out why the hx-get ended up in the wrong spot or why OOB swap is glitching out. D* morph just works.
- No need for hidden form <input> to submit client state, D* signals are cleaner and easier to use.
- No more micro-routes for targeted element updates to avoid hx-swap butchering page state. One route per page, just render the whole thing and morph takes care of the rest. Immediate-mode rendering and fat morphs removed ~50% of our routing table.
- SSE + fat morph is a superpower. This is view = f(state) done right.
We've had very few issues, D* just works and gets out your way. The team has really created something quite exceptional.The great news is htmx4 is adopting many of these ideas, so I recommend trying both and seeing what fits you best.
Once you want realtime/collaborative app SSE + morph lets you do that easily. Add streaming compression and this approach is suddenly crazy bandwidth efficient.
For people coming from react this gives you v = f(state) over the wire.
Lastly signals handle the edge cases where an out of bound morph would nuke your ephemeral client side state (mostly text input).
You can do this in htmx but you are fighting the design the whole way. Turbo is a bit better but doesn't have signals.
[1] https://dev.37signals.com/a-happier-happy-path-in-turbo-with...