If you don't want to use Alpine for whatever reason, you can just write your own javascript, you can use hyperscript, you can use some other inline scripting library.
Mr. HTMX touches on it in one of the essays: https://htmx.org/essays/hypermedia-friendly-scripting/
> when I need to work with json - since I don't control all backend and json isn't really a first class citizen of htmx
yeah, if you can't make the backend return HTML, you're in a worse off place if you want to use htmx.
There's extensions [1][2] for receiving and rendering JSON responses with htmx (though I haven't used them), but I totally understand it starting to feel like a worse fit.
1 - https://github.com/bigskysoftware/htmx-extensions/blob/main/...
I have a blog post in the works for this feature, here's a small code sample I made to show the idea:
<div class="card"> ╾──────────────╮
<header class="card-header"> |
<a |
class="button is-link" |
title="Load links for #167" |
role="button" |
aria-expanded="false" |
href="/app/notes/167/links" |
hx-trigger="click once" |
hx-boost="true" |
hx-push-url="false" │
hx-target="closest .card" ╾─╯
╭───╼ hx-swap="beforeend show:none"
| ><b>±</b></a>
| <a
| class="card-header-title"
| href="/app/notes/167"
| hx-boost="true"
| hx-target="#note"
| hx-swap="outerHTML transition:true show:window:top"
| >#167 Velificatio</a>
| </header>
╰╼
</div>- htmx is more straightforward (because a lot of the magic basically happening in the backend) and helps a lot to keep some sanity.
- Alpine shines when you need more composition or reactivity in the frontend. But it gets verbose quickly. When you feel you are reimplementing the web, it means you went too far.
For pagination, page structure, big tables, confirmation after post etc. I usually go with htmx. Modals, complex form composition (especially when you need to populate dropdowns from differents APIs), fancy animations, I prefer Alpine. (I probably could do that with htmx and wrapping it in a backend - but often more flexible in the frontend directly.)
To me, the main reason why I use these libraries, is what I write today will still be valid in 5 years without having to re-write the whole thing, and it matters since I have to maintain most of what I write.
One never uses just one JS lib :) The JS ecosystem always comes with lost of tools, and libs, and bells, and whistles.
I like Elm for this reason. Less choices. Zero runtime errors (I know it is possible in contrived examples, but I've seen and many teams have said the promise holds true after many years of using in production).
HTMX achieves its composability by declining to have opinions about the hard parts. React's ecosystem exists because it abstracts client-side state synchronization, and that inherent complexity doesn't just disappear. When you still have to handle the impedance mismatch between "replace this HTML fragment" and "keep track of what the user is doing", you haven't escaped the complexity. You've just moved it to your server, and you've traded a proven, opinionated framework's solution for a bespoke one that you have to maintain yourself.
If anything, the DOM being a shared substrate means JS frameworks are closer to interoperable than native GUI toolkits ever were. At least you can mount a React component and a Vue component in the same document. They're incompatible with each other because they're each managing local state, event handling, and rendering in an integrated way. However, you can still communicate between them using DOM events. An HTMX date picker may compose better, but that's just because it punts the integration to you.
Ecosystems have their downsides too. Just a small example, no htmx users were impacted by the React Flight Protocol vulnerabilities. Many htmx users have no-build setups: no npm, no package.json, nothing. We don't have to worry about the security vulnerability treadmill and packages and tools arbitrarily breaking and no longer building after some time passes. We just drive the entire webapp from the backend, and it just works.