(Disclaimer: I haven't actually run into a case where I had to move from HTMX to a SPA framework, even partially, so this is largely an educated guess)

I think this scenario would either be very apparent early on in the project, or wouldn't actually be that challenging. There are a couple ways you could run into the limits of HTMX:

1. You require purely client side interactivity. The right (IMO) way to use HTMX is as a replacement for sending JSON over the wire and rendering it into HTML on the client, so if your app has features that _wouldn't_ be done that way, you should reach for something else. Fortunately there's lots of solutions to this problem. You can use built in browser features to achieve a lot of the basics now (e.g. the <details> tag means you don't really need custom scripts if you just want an accordion), write simple vanila scripts, or adopt light weight libraries like alpinejs or the creator of HTMX's (only slightly deranged) hyperscript.

2. Maybe your purely client side interactivity needs are complex enough that you do need a SPA framework. At that point you can adopt the islands architecture and create interactive components in your fraemwork of choice, but continue to use hypermedia to communicate with the backend.

3. If you can't easily separate client side state (handled with javascript, potentially with the aid of frameworks) from server state (handled on the server and sent to the client via hypermedia), you can again adopt the islands architecture and have your islands manage their own network requests to the backend.

4. If the above applies to all of your app, then hypermedia/HTMX is a bad fit. But this should generally be pretty obvious early on, because it's about the basic, fundamental nature of the app. You probably know you're building google docs when you start build google docs, not mid-way through.

multicards is almost purely client side interactivity. I STILL use htmx for a number of reasons:

- No JSON serialization: HTMX sends form data natively no JSON.stringify() needed - Less JavaScript: Declarative hx-* attributes replace imperative fetch code. in my world declarative always wins. - Automatic headers: HTMX handles X-User-Id and other headers configured globally - Built-in error handling: hx-on::error instead of .catch() chains - Swapping flexibility: Can show success/error feedback via hx-swap without custom JS - Request indicators: Free loading states with hx-indicator - Debugging: HTMX events visible in browser devtools; fetch requires console.log

and most all: performance. multicardz goes like stink. 100/100 lighthouse scores, First Contentful Paint 0.4 s, Largest Contentful Paint 0.5 s, Total Blocking Time 0 ms, Cumulative Layout Shift 0, Speed Index, 0.5 s

still prerelease, but cautiously hope to go general availability by and of year.

You won't keep those performance numbers if the network conditions are bad, unfortunately. For things that require a network round trip, that's fine, because doing it via JSON (or some other serialization format) won't save you anyway. On the other hand, if it can be done entirely on the client, adding network round trips will slow the interaction down. It sounds like you're mostly doing the former (otherwise loading indicators and serialization wouldn't matter), but it's a point that should still be emphasized.

I think you misunderstood me. I use htmx where most people would use fetch. I do not just use htmx willy nilly for no reason.

I use pure front end manipulation to set state, then I send the state to the stateless back end with pure functions, and I get amazing performance: www.multicardz.com public test bed, 1M records, round trip usually around 160 ms for anywhere between 1 to 100K hits