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