Back to writing
Javascript · HTML · React

Is "dumb HTML" really killing React? The honest case for HTMX

/ / 6 min read

HTMX is 16KB that lets HTML talk to the server and swap in the reply. One company cut 67% of their React code with it. Here's when it wins and when it burns you.

A single HTML button firing a request to a server and swapping in the HTML that comes back, with no client-side JavaScript
On this page

Here is a button. You click it, the number changes, fresh from the server, no page reload. Now the strange part: there is no JavaScript here. None that you wrote. The whole thing is one HTML attribute.

And one real company used this idea to delete 67% of their React code.

So is "dumb HTML" really killing React? Let me settle it, including the parts the HTMX fans quietly skip.

One attribute instead of five

To make that one number update the modern way, you reach for React. A component, a piece of state, a fetch call, a JSON endpoint on the server, and a re-render to stitch it back together. That is a lot of moving parts for one number on a screen.

HTMX throws all of it out. The trick is almost insultingly simple: let plain HTML talk to the server directly and swap in whatever HTML comes back. Dumb, and it works.

The internet is split down the middle on whether that is genius or a step backwards. By the end of this you will know when to reach for it and when it will burn you.

The weight

Start with the weight. HTMX is about 16KB, zero dependencies, plain JavaScript you never touch. React plus React DOM, just the core before your app does anything, is roughly 45KB. A real single-page app ships hundreds of kilobytes before it shows you a thing.

HTMX was made by Carson Gross, a computer science professor in Montana, not a framework team with a trillion-dollar company behind it. The entire loop is three words: request, response, swap. You add an attribute, the element fires an HTTP request, the server sends back a chunk of HTML, and HTMX drops it into the page. That is it.

The four hx- attributes

Here is the anatomy. hx-get or hx-post says where to send the request. hx-target says which element should change. hx-swap says how: replace the insides, replace the whole element, or just add to it. hx-trigger decides when it fires: a click, a key press, a form change, even a timer every couple of seconds for a live dashboard.

<button hx-get="/clicked" hx-target="#count" hx-swap="innerHTML">
  Click me
</button>
<span id="count">0</span>

That button hits /clicked, takes the HTML the server sends back, and drops it inside the span. No component, no state, no JSON.

Now the part that breaks the framework habit. It isn't only buttons. Any element can make a request. Any event can trigger it. Every HTTP verb is on the table: get, post, put, delete, not just the two that HTML forms ever gave you. And you pick exactly which part of the page gets replaced. If you have ever wired behaviour onto markup by hand, this is the clean version of that instinct. I wrote a whole piece on custom HTML and JavaScript attributes that this builds straight on top of.

Hypermedia, and real REST

So why does returning HTML instead of JSON matter so much? Because of an old idea with a fancy name: hypermedia. The server doesn't just send data. It sends the next set of actions baked into the HTML. The page itself carries the state of your application.

Here is the part that starts arguments. This is REST. The real REST, the way Roy Fielding actually defined it. Somewhere along the line "REST" got hijacked to mean "a JSON API". HTMX is just quietly going back. If you have only ever known REST as JSON endpoints, my practical breakdown of REST, GraphQL, and gRPC is worth a read alongside this.

It also brings back something we lost: locality of behaviour. Look at the element and you can see what it does, right there in the markup. No hunting through a dozen files to trace one click.

The receipt

Now the receipt, because "less code" is easy to claim and easy to fake.

A real company, Contexte, rewrote their React app in HTMX. The result: 67% less code. Their JavaScript dependencies dropped from 255 down to 9. Build times fell by nearly 90%.

This is no toy. HTMX sits at 48,000 stars on GitHub, was the number one rising star in front end, and lands as one of the most admired tools in the big developer surveys.

The reason the code shrinks is structural. In the React world you keep state twice, once on the server and once in the browser, and you write an API forever just to keep them in sync. HTMX keeps a single copy on the server and sends HTML. A whole category of sync bugs simply stops existing. It is the same "the framework was quietly costing you" argument I made about runtime UI libraries being tech debt you can't see.

The HOWL stack

Because the server only needs to return HTML, your backend can be anything. The community even has a name for it: the HOWL stack, hypermedia on whatever you'd like. Django, Flask, FastAPI, Rails, Laravel, Go, Express. Pick your language. HTMX does not care.

When you do need real client-side interactivity, a dropdown, a toggle, a small animation, you reach for a tiny partner like Alpine.js or Hyperscript. Small tools sprinkled in where you need them, instead of one giant framework running everything.

If this reminds you of Rails Hotwire and Turbo, you're right. Same instinct, different flavour. Turbo is more opinionated and batteries-included. HTMX is lower level and does only what you explicitly tell it to.

The comments war

Now the comment section, because this is where the real fight is.

The most-liked objection: isn't this just Ajax and jQuery reinvented? Honestly, kind of, yes. Veterans who did this back in 2010 are watching the web close a full circle. HTMX's answer is that it took that old instinct and turned it into a clean, declarative attribute system instead of a pile of hand-wired scripts.

Objection two: "no JavaScript" is a lie. Fair. HTMX is JavaScript. The honest claim is no JavaScript that you write.

Objection three, the real technical one: every action is now a network request. On a slow connection a snappy app can crawl. That is a genuine trade-off, and it is exactly why those tiny partner libraries exist. This is not magic. It is a different set of trade-offs.

When not to use HTMX

Let me be honest here, because HTMX fans often aren't.

This is the wrong tool for some apps. A spreadsheet like Google Sheets. A map you drag in real time. Anything offline, or with thousands of interdependent widgets reacting instantly. That is React's home turf and it isn't close.

The skeptics have a point on adoption too. You'll see HTMX all over solo projects and side projects, and far less inside big enterprise front ends for now.

So no, this is not React's funeral. If you're building a deeply interactive client application, reach for React. That is what it's brilliant at. HTMX is for the other 90% of the web: forms, dashboards, content CRUD, the boring stuff that secretly makes up most of everything.

The verdict

Quick recap. HTMX is about 16KB that lets HTML talk to the server. It swaps in HTML instead of juggling JSON. It revives real hypermedia and real REST. And for most apps it deletes a staggering amount of complexity.

The team now calls the 2.x line feature complete, and HTMX 4 is already in beta, folding in DOM morphing and streaming responses. The pitch hasn't changed since day one: do more by writing far less.

The instinct behind it is the same one I keep coming back to: most projects are carrying far more machinery than the job needs, the same way 90% of projects never need more than SQLite. HTMX is that argument pointed at your front end.

What to do now

Pick the smallest thing in your current app that shells out to React for no good reason. A search box that filters a list. A "load more" button. A form that posts and updates one panel. Rebuild that one piece with four hx- attributes and a server route that returns HTML. If it feels lighter, you've found where HTMX belongs in your stack. If it feels slower, you've found where it doesn't. Either way you learned it in an afternoon, not a rewrite.

FAQ

Frequently asked

HTMX is a ~16KB JavaScript library that lets plain HTML elements make HTTP requests and swap the returned HTML straight into the page. You add attributes like hx-get and hx-target to an element, it fires a request on an event you choose, the server sends back a chunk of HTML, and HTMX drops it into the page. The whole loop is request, response, swap. You never write the JavaScript yourself.

Neither is better in the abstract, they solve different problems. HTMX wins for forms, dashboards, and content-heavy pages where most of the state lives on the server. React wins for deeply interactive client apps like spreadsheets, live maps, or offline tools with thousands of widgets updating at once. Pick HTMX when a page is mostly server-driven, and React when the browser genuinely needs to own the state.

No, and its own creators say so. HTMX handles the roughly 90% of the web that is forms, dashboards, and CRUD, where returning HTML from the server is enough. It is the wrong tool for real-time, offline-first, or heavily interactive client applications. Those are React's home turf and it isn't close.

No. HTMX is itself written in JavaScript, so JavaScript still runs. The honest claim is no JavaScript that you write. When you do need small client-side interactivity like a dropdown or a toggle, you reach for a tiny partner library such as Alpine.js instead of a full framework.

Any backend that can return HTML. The community calls it the HOWL stack, hypermedia on whatever you'd like. Django, Flask, FastAPI, Rails, Laravel, Go, and Express all work fine because HTMX only cares that you send back HTML, not JSON.

Enjoyed this? Let's talk.

Start a conversation →