I was able to find architectural patters that work smooth as glass.
Here is what my htmx apps have: - Single-purpose endpoints: Each endpoint returns ONE thing (a card list, a tag cloud, a form fragment) - Optimistic UI: Preferences like font/theme update the DOM immediately; the save is fire-and-forget with no response needed - Simple error handling: Most endpoints either succeed (return HTML) or fail (HTTP error code) - No fragment orchestration: Not returning 3-5 fragments; using hx-swap-oob sparingly
Here is how I update fonts on screen in user prefs: User selects font → JS updates body class immediately → htmx.ajax() saves in background → done
vs. the anti-pattern you're describing:
User submits form → backend validates → returns success fragment OR error fragment OR partial update OR redirect signal → frontend must handle all cases
No language or programming paradigm is perfect. All programming is an exercise in tradeoffs. The mark of a good CTO or architect is that ability to draw out the best of the technology selection and minimize the tradeoffs.
Please do a write up of the best practices you've found. I tried htmx a few years ago for a side project and while I appreciated the simplicity of a lot of it, I had trouble understanding how/when to use it and in what ways. I think I was trying to contort it too much into my understanding of api/spa. That or my interactivity needs were too complex for it, I can't tell.
These days, I admit, though, the ship has sailed for me and htmx. My main app frontend is React and since the LLMs all know much more than I do about how to build out UIs and are 100x faster than me, I'll probably be sticking with React.
Here's an example offline-first hypermedia-driven soccer application. The match page is the most complex part of the application and I use Morphdom to just do a diff on the main section of the page. I find hypermedia-driven development to be super simple.
I find React to be really complex. What normally takes me just some HTML rendered from the back end and some interactivity on the front end can be done in just a few lines of code, but React takes 10s of lines of code for what I can write in a single line of code using vanilla js. The virtual dom causes it to make everything state. I always find it odd that people reach for that as their front end. I could understand something like Svelte, but even that is too complex for my needs. But I'm always writing CRUD apps, so there is some complexity but not that much, React just makes something that was simple, super complex.
https://github.com/jon49/Soccer
That is what DATAOS.software is all about. It is a manifesto of my proposed best practices somewhat like Hypermedia Systems, but more hands on, more of a cookbook.
Interesting read. I haven't quite finished it all. I haven't ever needed anything like that when writing web pages with HTMX, html-form (my own), nor htmz-be (another one I wrote based off of htmz but the back end decided where the HTML will go, similar to data-star and nomini). When I write code from the back end and target the front end I can use middleware to common updates.
Here's the most complex app I've made with it. The most complex part of the app is the match page. I just use morphdom for that part of the app and it makes it super easy, I just send the whole main part of the page back and let a dom diff happen.
https://github.com/jon49/Soccer
How do you handle HTTP errors?
Just curious because when I used HTMX I didn't enjoy this part.
I like to return errors as text/plain and I have a global event handler for failed requests that throws up a dialog element. That takes care of most things.
Where appropriate, I use an extension that introduces hx-target-error and hx-swap-error, so I can put the message into an element. You can even use the CSS :empty selector to animate the error message as it appears and disappears.
Usually the default behavior, keeping the form as-is, is what you want, so users don’t lose their input and can just retry.
Honestly? I never think about it. I've never had to. What did you run into? Curious what the pain point was.
I had a site where the user can upload a file < 5MB. There may be a way to check this on the frontend, but for security reasons, it has to be checked on the backend too.
If it exceeds it, I returned 400. I had to add an event listener to check for the code (htmx:afterRequest) and show an alert(), but this gets difficult to manage if there's multiple requests to different endpoints on the page. Looking at it now, maybe I should have configured HTMX to swap for 4xx.
I have something similar on my website, and my solution was to make server driven modal/toast responses.
Allow the server to return a modal/toast in the response and, in your frontend, create a "global" listener that listens to `htmx:afterRequest` and check if the response contains a modal/toast. If it does, show the modal/toast. (or, if you want to keep it simple, show the content in an alert just like you already do)
This way you create a generic solution that you can also reuse for other endpoints too, instead of requiring to create a custom event listener on the client for each endpoint that may require special handling.
If you are on htmx's Discord server, I talked more about it on this message: https://discord.com/channels/725789699527933952/909436816388...
At the time I used headers to indicate if the body should be processed as a trigger, due to nginx header size limits and header compression limitations. Nowadays what I would do is serialize the toast/modal as a JSON inside the HTML response itself then, on `htmx:afterRequest`, parse any modals/toasts on the response and display them to the user.
Good idea, thanks for sharing! Nice design also
hx-trigger in the response header would handle that cleanly. Fires an event client-side; one global handler shows the error.
Similar to wvbdmp's approach but without needing the extension
See https://dev.to/yawaramin/handling-form-errors-in-htmx-3ncg
I have never loved the idea of the server rendering HTML which is probably why I have such a hard time with HTMX. In every other paradigm you clearly separate your server API and UI rendering/logic. Web apps are the only place where it seems common to have the server render UI components. Imagine if you had a Java or Swift application and had the server sending your phone UI screens. I don’t even know how you would pitch that. About the only thing I have seen that makes some sort of sense here is video game rendering to be able to play on really limited devices with quick internet access.
The problem with SPAs is the ecosystem. I recently found packages like this [1] and this [2] in my node_modules and that is insanity. But the architecture honestly makes way more sense than any other paradigm: server side is a well defined API and the client renders UI and handles local state.
[1] https://www.npmjs.com/package/isarray
[2] https://www.npmjs.com/package/is-string
X (the Window System not the thing that was Twitter) explicitly allowed a remote machine to send rendering commands over a network to the local machine? (I'm avoiding using the term "server" as X has this round the other way - from the users perspective the server is local and the client can be remote).
Sun's NeWS also allowed something similar - but with a large amount of programmability using PostScript.
Sure but that was with the idea that everything happens synchronously. TeamViewer also renders the UI remotely. Any system where the client actually does any state management and not just pixel/character rendering does not use this. While the X system did allow this, real world systems did not use any of these remote rendering commands besides “render pixels”.
At the end of the day, personal preferences play a huge role. All programming is a compromise between tradeoffs.
React has a lot going for it. It's simply that I prefer htmx; it feels cleaner to me.