Ben Bleikamp Ben Bleikamp

From React to HTMX and back to React

When trying to keep things simple actually makes things more complex.
From React to HTMX and back to React

After spending an inordinate amount of energy trying to never touch React in 2023 we are, to my surprise back on React. Maybe the most surprising part is: it’s been a welcome, even delightful change.

We move faster, we can ship more polished UI, and we are able to leverage modern and up to date tools and libraries.

Before the move, our frontend looked like:

Is everything we do possible with HTMX and AlpineJS? Of course. At the end of the day, it’s all just JavaScript, HTML, and CSS. But we found ourselves jumping through hoops to make that stack work and at the end of the day it wasn’t worth the effort. Things didn’t even feel simpler!

This architecture worked initially, but component reusability became a bottleneck as our application complexity increased. We were writing a ton of boilerplate code and the team wasn’t familiar with Alpine’s patterns and APIs—building new components was a huge chore.

Keeping What Works

To start, we did not go all in on React. We still think GraphQL is one of the biggest mistakes in modern web development history. And we are appalled by server side components.

So our Django backend remains unchanged - it’s battle-tested and remains the source of truth for our application’s state. (A previous attempt at React + Rails + GraphQL + ActiveRecord taught us the importance of clear architectural boundaries.)

We ended up with the TanStack ecosystem, specifically Tanstack Query and Tanstack Router, for the focused, well-architected libraries and the community around them. This keeps our frontend in sync with our backend.

Does it feel like a local first app? Of course not. But it’s fast enough for our purposes.

Why React?

1. Components

React’s components are still in terms of productivity and developer experience. They are composable, easy to understand, easy to debug, and there is a bunch of tooling around working with them in the browser.

2. Composition

React excels at breaking complex interfaces into reusable pieces. This modularity has accelerated our development cycles and improved code maintainability.

The one trick for us is avoiding trying to do too much DRY-ing too early. We only refactor when things get painful.

3. Battle-tested Libraries

The React ecosystem provides production-ready, accessible components that integrate seamlessly with our design system.

We are using Radix Themes as the base for our design system, I’ve already mentioned Tanstack Query and Router—we don’t need to go through all the available libraries in React, but I think it’s safe to say the ecosystem and community are strong.

4. Developer Productivity

React’s declarative model and state management patterns have improved our ability to build sophisticated interfaces. The development experience is more predictable, and debugging is straightforward.