← Back to context

Comment by perardi

23 days ago

I did.

My startup did.

And now we’re going to rip it all out and move to a React front-end.

HTMX makes response handling much more complex. Every endpoint returns 3–5 different HTML fragments. Frontend and backend must agree on every scenario — success, validation errors, system errors, partial updates, full reloads.

And HTMX is still a fairly obscure library. The documentation and examples are lacking, there isn’t a real set of established best practices at scale, and not for nothing, LLMs aren’t great at it.

React is mature, used at scale, provides separation of concerns, and is great for agentic AI coding. HTMX has its place for simple projects, but for anything non-trivial, it’s a no for me.

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.

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

      1 reply →

    • 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

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

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

      1 reply →

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

      https://www.reddit.com/r/iOSProgramming/comments/1khv43o/com...

      'This technique is known as Server Driven UI and it is used by Uber, AirBnb and several other big players. The idea is to change the UI instantly without submitting a new version. Developer can just add a new entry in JSON, which can map to an existing component (already available in the binary) and then that component gets displayed on the screen.'

      If you pitch to your business that you can update the app automatically without an app store submission, they will start salivating, if not foaming at the mouth.

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

> Frontend and backend must agree on every scenario — success, validation errors, system errors, partial updates, full reloads.

Well, frontend and backend always need to agree on every scenario, that's why I prefer to do validation on backedn and frontend to just display it and not do any validation.

  • That makes for some nasty debugging and unsafety. Both sides should parse both times, unless you're encountering real (not imaginary) performance issues.

    As someone who's been parsing everything entering the system from 2018, I don't believe you can have performance issues by parsing the data entering the system, the only exception I can name in a decade was real time trading app where the data coming in all time was just gargantuan that parsing it all the time was impacting UX and even then there should be an argument for the backend insisting on sending whole data instead of the latest value.

    • Frontend and backend will always diverge and 90% of your bugs will be around that. Mitigating the divergence is the primary goal of every web framework, both backend and frontend, when you sit back and think about it.

> and is great for agentic AI coding.

Definitely sad to see this everywhere nowadays, tech choices made because of AI

  • We are locking in path dependence on flawed technologies because by nature newer technologies lack the training distribution needed for good LLM output. Our industry is in a pretty dismal state.

I found the book (hyper media systems) to be better at explaining full integration than the library site, which gives nuts and bolts and big picture, but not much intermediate info.

> Frontend and backend must agree on every scenario

When is this not the case?

  • I suspect the hidden assumption here is that frontend and backend are written by different people/teams with a narrow interface between them. Because they use different technologies and build tools it’s easy for them to end up being competely siloed, which IMO is one of the worst aspects of how webdev evolved in the last 20 years.

    Thus, it’s considered normal that the backend team spits out some JSON and doesn’t know or care what the frontend team does with it.

    With HTMX that distinction doesn’t exist so much (the frontend consists of fragments generated by the backend) so you will need a different organizational approach. The “frontend” folks will need to write a lot of “backend” code, but presumably in a separable layer.

    • It is true that htmx requires some straddling backend and frontend. I think the organizational approaches that split them is dumb to begin with personally. Good UI/UX almost always impacts the backend.

  • When an API returns JSON, your JS framework can decide what to do with it. If its returning HTML that's intended to go in a particular place on a page, the front-end has far less flexibility and pretty much has to put it in a specific place. Hence why they said endpoints can return 3-5 different versions of HTML.

    • > When an API returns JSON, your JS framework can decide what to do with it.

      The JS framework is the frontend, so you're still coordinating.

      > If its returning HTML that's intended to go in a particular place on a page, the front-end has far less flexibility and pretty much has to put it in a specific place.

      Well yes, because presumably that's what the app is supposed to do. If it's not supposed to put it in that place, why would that be the specified target?

      If this kind of static assignment of targets is not flexible enough for some reason, then use OOB updates which lets you replace fragments by id attribute. That lets you decouple some of these kinds of decisions.

      Although "endpoints can return 3-5 different versions of HTML" is also a bit of a red flag that you're not using htmx correctly, generally endpoints should be returning 1, maybe 2 fragments in unusual cases.

      In any case, you might find DataStar more to your liking, it's partway between React and htmx.

      3 replies →

    • "framework can decide what to do with it" sounds like a feature (more flexibility) but is actually often the source of errors and bugs.

      A single, consistent, canonical response, generated by the server, taking into account all relevant state (which is stored on the server) is much cleaner. It's deterministic and therefore much more testable, predictable and easier to debug.

      For pure UI-only logic (light/dark mode, etc) sure you can handle that entirely client-side, but my comment above applies to anything that reads or writes persistent data.

It's terrible, why would I want my endpoints to return random HTML fragments? I realize thats how you did it in the JQuery times, but I was never in those - at that time we simply had template engines in the backend so this HTML slop wouldn't contaminate everywhere..

Most of the frontend stuff I do is for internal pages on embedded devices, and I'm very happy with a structure where I have the frontend being a full React fancy component lib SPA that is eventually just compiled down to a zip bundle of files that the backend needs to know nothing about and can serve as dumb files. The backend is a JSON API of sorts that I would need to build anyway for other use cases.

  • Returning HTML sounds like a styling nightmare, if anyone changes the structure, unintended consequences. Plus it’s difficult to reason possible states of the UI with fragments sitting on the server, possibly dynamically built on the server. Very jquery/PHP ish. I had my fun and don’t want to go back.

    • To "get" HTMX, you have to think server-first. State is persisted on the server and all state-change logic is performed on the server (often triggered by http requests from a "dumb" client).

      If you hang on to "possible states of the UI" that are client-side only then yes you'll have some difficulty implementing server-generated HTMX responses but more importantly, when your client has state that sometimes isn't in sync with, or shared with, or validated by your server, you're setting yourself up for errors and bugs that will exist regardless of framework.

      In short, HTMX forces you to apply "single source of truth" concepts to your application.

    • Clearly you haven't used something like HTMX. Do you understand what "returning HTML by the server" mean? You are basically sending back a view, like you would in any other framework actually. This would be the exact same pattern as displaying or dynamically adding a new component from either React or Vue. It doesn't create any styling issue at all, nor any unintended consequences.

      4 replies →

  • > It's terrible, why would I want my endpoints to return random HTML fragments?

    What would you return instead? It's easy to generate HTML, because that's what your server is already generating (and that's about all it should generate).

    • HTML is the last thing I would ever want to generate on my embedded device, it's a terribly verbose string-based mess invariably coupled with stylistic choices. Which is why my servers don't generate any of that, they serve static files - and any interactive information in something that looks a lot more like an interface definition.

      15 replies →

Real world examples with error handling would be great for HTMX. Now in the LLM era you might get away without those. I just don't understand why can't we have complete documentation for the most basic scenarios.

So first you choose a nicher solution you didn't fully understand and now you jump into another one (full of issues but popular) you likely don't understand the trade offs too?

Just to be completely clear... you do not need React just so you can turn JSON into HTML. HTMX can 100% can do that.

You're argument is fine assuming you wish to become another react frontend in a sea of react frontends.

But the documentation example is a terrible argument, the benefit of HTMX is it is easy to understand what is actually happening. There is no magic, you don't need to dive through millions of lines of code to figure out what this is doing like react. It's very basic javascript. Just read the library, frankly you don't even need any documentation. Just take 15 mins and read the entire library.

> Every endpoint returns 3–5 different HTML fragments. Frontend and backend must agree on every scenario — success, validation errors, system errors, partial updates, full reloads.

And why would that differ from React?

When I was building a website with React, I needed to model a "apply coupon" endpoint with different states (coupon applied, coupon does not exist, coupon exists but has reached its max usage limit) and it was so annoying because you needed to

1. The backend route that returns JSON with a different model depending on the coupon state

2. The JSON models for each response type

3. And then on the frontend you need to load the data, parse the JSON, figure out which "response state" it is (http status code? having a "type" field on the JSON?) convert the JSON to HTML and then display it to the user

In my experience it added a lot of extra "mental overhead". It is something that should be extremely simple that ends up being unnecessarily complex, especially when you need to do that for any new feature you want to add.

When using htmx, a simple implementation of that would be

1. A backend route that returns HTML depending on the coupon state

2. Some htmx attributes (hx-post, hx-swap) on the frontend to make the magic happen

Don't get me wrong, there are places that you wouldn't want to use htmx (heavily interactive components) but that's why htmx recommends the "islands of interactivity" pattern. This way you can make the boring things that would add unnecessary complexity when using React with htmx, and then you can spend the unused "mental overhead" with the interactive components. (which, IMO, makes it a more enjoyable experience)

At the end of the day it is just choices: Some people may prefer the React approach, some people may prefer the htmx approach. All of them have their own upsides and downsides and there isn't a real answer to which is better.

But for my use case, htmx (truth to be told: I use my own custom library that's heavily inspired by htmx on my website, but everything that I did could be done with htmx + some htmx extensions) worked wonderfully for me, and I don't plan on "ripping it all out" anytime soon.