Logo

Why I Stick With HTMX Even If It Sucks

While HTMX sucks, it's still the best option when it comes to building reactive web UIs in 2025

Published: September 12, 2025

A while ago, I wrote about the challenges I faced choosing HTMX over React for my project, ClaroHQ. I stand by what I said; building highly reactive UIs is genuinely harder with HTMX. And yet, if I were to start a new project today, I’d choose HTMX all over again.

Why stick with a tool that can feel like you’re coding with one hand tied behind your back? Because the “better” tool isn’t always better for the project.

The “Simple” Task: A Tale of Two Stacks

To illustrate my point, let’s consider a feature I mentioned in the previous post: building a dynamic invoice form where a user can add and remove line items before saving.

The React Approach: Clean, Structured, and Deceptively Complex

If I were to build this with React, I’d start by architecting a clean, component-based solution. But as the saying goes, “One does not simply use React.”

To do it “right,” the journey would look something like this:

  1. Separate Frontend and Backend: My Django backend would need to expose a set of JSON API endpoints for creating, retrieving, updating, and deleting invoice line items.
  2. State and Form Management: On the frontend, I’d pull in react-hook-form for efficient, uncontrolled inputs and manage the list of line items in the component’s state.
  3. Data Fetching: To handle API communication, I’d use Tanstack Query. This would involve setting up queries to fetch initial data and mutations to handle create, update, and delete operations. Each of these would require its own loading and error states.
  4. Type Safety: To prevent bugs between my API and frontend, I’d integrate Zod to define schemas and validate API responses, ensuring the data is exactly what my components expect.

This approach is structured, type-safe, and robust. However, it transforms a single feature into a mini-project. I now have two separate codebases to maintain, a complex web of dependencies in my package.json, and a significant amount of boilerplate code just to get data from the server to the screen.

The HTMX Approach: Embracing Server-Side Power

Now, let’s build the same form with HTMX, sprinkled with a little Alpine.js for client-side interactivity.

  1. One Backend, One View: My Django application handles everything. I create a view that renders the main invoice form.
  2. Adding a Line Item: I add a button: <button hx-get="/add-invoice-item" hx-target="#line-items" hx-swap="beforeend">Add Item</button>. When clicked, HTMX calls a simple Django view.
  3. The Magic of HTML Fragments: This new view doesn’t return JSON. Instead, it renders just the HTML for a single new line item (a partial template) and sends it back. HTMX takes this HTML fragment and appends it to the form.
  4. Handling Dynamic Forms: I use Django’s built-in formsets to manage the collection of line items, and a touch of Alpine.js to handle any minor client-side needs, like hiding a “remove” button if there’s only one item left.

The result? No new build steps, no API endpoints to document, and no complex state management libraries. I’ve leveraged the tools my backend framework already provides, and the entire logic lives in one place. It might not be as “clean” in a component-based sense, but it’s drastically simpler to build and maintain.

The Wisdom in Constraints

By choosing a simpler tech stack, I’m forced to be more deliberate. I can’t build every flashy UI I can imagine, but this limitation is a feature, not a bug. It channels my focus toward the core functionalities that provide real value to users.

This stack encourages creativity within its constraints—finding clever ways to store state in the DOM or using browser events to create reactivity. It turns out that for a huge portion of web development, this is all you need. I don’t need to add 20 dependencies to my project to build a feature that my backend framework is already well-equipped to handle.

Conclusion: Choose the Right Tool for the Job, Not the Hype

The debate between HTMX and React isn’t about which is definitively better, but which philosophy you adopt. React offers a powerful, client-centric model that excels at building complex, app-like experiences. But that power comes with the overhead of managing a separate application, a complex toolchain, and a significant amount of client-side state.

HTMX, on the other hand, reminds us that server-rendered HTML is still incredibly capable. By extending HTML’s capabilities, it allows you to build modern, dynamic interfaces without abandoning the simplicity and robustness of a traditional web application. For me, that means less time wrestling with tooling and more time delivering features. And for my projects, that’s a trade-off I’m happy to make every time.

💡 Need a Developer Who Gets It Done?

If this post helped solve your problem, imagine what we could build together! I'm a full-stack developer with expertise in Python, Django, Typescript, and modern web technologies. I specialize in turning complex ideas into clean, efficient solutions.