Mobile browsers will do all sorts of optimization, such as interrupting the network, slowing down the vm, putting it to sleep, caching and uncaching things without letting you know, and without a predictable pattern.
If you use raw JS, you can deal with all kinds of errors manually, put in place recovery strategies, bust caches, etc.
With HTMX, you just get sluggish behavior, or no behavior at all in your page, and you don't know why.
Also like another person said, you expect your state to be the same, like the scrolling placement, but chrome might decide that no, you get a page refresh there, or you are somewhere else in the page on next switch.
In this particular app, I have a raw JS counter, which is updated on the client to make it snappy, and by htmx to keep it up to date with other modifications. But the counter will be off randomly because Chrome messes with it. So I had to manually put many rules to know it's out of sync, and request the sync at the right moment. But the sync may not happen because Chromes decided so. So I should try several times, with exponential backoff, differentiates the different reasons of failures and update the DOM manually while handling various interactions with other components.
At this stage, you are basically coding a lot in JS instead of getting the state from the server in HTML, so having VueJS + VueRouter + Pinia is going to be easier to manage, and you'll get more interactivity and optimistic updates on top.
It's not worth it. Right tool for the right job and all that.
It's mostly on mobile though. On Desktop, the HTMX app behaves perfectly.
About the state: there are plenty of ways to have a polymorphic backend responding with fragments or entire HTML pages, depending on state and what's required by the request. Can't see the limitation you guys are talking about.
About the scrolling position, it's actually dynamically loaded content that messes everything. Browsers do a pretty good job keeping scrolling position, as long as the page loads with the same content as before. Which is easy with htmx and very hard to impossible with dynamic content.
For example to implement an infinite scroll, you can use the htmx DSL to load additional rows like this: https://htmx.org/examples/infinite-scroll/
If I did this with react, I can use a session storage caching plugin, so how do you prevent the chain of load events on history back and page refresh with htmx?
Now you are looking at service workers...
I mean with a bit of extra JS and some additional APIs, nothing is strictly impossible but it's often that you go back to the architecture board when you are working with it.
I don't dislike it though, not even close. React (and other similar tools) has (have) a place, so does htmx.
You could use hx-push-url [1] every time the scroll triggers loading more rows, updating the total number of rows loaded. When the browser refreshes the page, the backend will know how many rows to return. No need for complicated JS plugins and service workers. Just basic browser feature, HTTP and HTML. You have fewer ways of shooting your own foot.
I think the modern frontend environment have a tendency to look for over complicated solutions.
Most times I see people proposing JS to manipulate the browser, a simpler browser-based solution would be perfectly good.
In most cases when I browse the web, the JS manipulation leads to very poor UX.
Even when the developer is exceptionally good and can deliver better solution than the browser, the advantage gain is so small that it's not worth the effort. Unless you're Facebook and can dillute the high-quality development cost to billions of users.
HTMX has pretty simple controls for pushing history state from either the client or the server for each request.
Add the current page into the URL every time you load a new section and when someone hits 'back', they can be given exactly the same content as they had before
Developers are taught to overkill everything. They implement things naively, admired of how "smart" their "solution" look, compared to a "dumb" browser.
They shoot themselves in the foot all the time. Users suffer with bad UX. Projects move slowly and expensively. Everyone loses.
Depending on RAM limitations, the mobile browser will kill the tab session. When the user comes back, it'll reload the page. But I don't see how this is different for htmx or JS websites.
I found this to be the biggest issue when building my webpage, I wanted to have a link like /blog/foo, but what exists out there is just / and the documents at /blog and /blog/foo are just the small fragments that get loaded once you click your way through / Ultimately I hacked around it by adding some js to every file beyond /, which redirected to / with some anchor, and having / restore the state through the anchor, but it doesn't look the same as regular links into a website (/#blog-foo vs /blog/foo)
I see two scenarios:
1. User interacts triggering "/blog/foo", which should return a fragment
You can add a "?fragment=true", or a custom header, or hidden input indicating the backend the desired behavior.
2. User's mobile browser reloads "/blog/foo"
Respond with the entire page, including the fragments as if the user had interacted each step of the way.
Seems doable and not that much of a hassle as fragment replacements should be simple afterall, but I'm simply running my site as a static page for now and I had to hack a redirecting extension for things to sort of work.
Huh? /blog/foo should return the full document. Why did you do it so it depends on the user clicking through links in a certain order?