For about three years now, HTMX has been the framework you cannot avoid in developer Twitter, Hacker News threads, and conference talks. It is positioned, by its creators and most of its evangelists, as a radical alternative to the single-page application — a way to build interactive web interfaces without React, without TypeScript, without a build step, by extending HTML with a small set of attributes that let any element issue AJAX requests and swap server-rendered HTML into the page. The framing is genuinely refreshing. It is also, for anyone who wrote ASP.NET in 2007, unmistakably familiar.
The pattern HTMX is selling — server holds the canonical state, click an element, server returns an HTML fragment, swap it into a target on the page, no client-side state machine to maintain — is, almost exactly, what UpdatePanel and the ASP.NET AJAX Extensions were doing two decades ago. The implementation is radically different. The architectural shape is the same. And the reason HTMX is succeeding where UpdatePanel got dismissed is, in retrospect, one of the more useful lessons the WebForms era left to the modern web.
What UpdatePanel actually did
Before getting to HTMX, it is worth being precise about what the older pattern looked like, because the comparison only works if both halves are remembered accurately.
UpdatePanel arrived with the ASP.NET AJAX Extensions in 2007 and became part of the framework proper with .NET 3.5. The model was straightforward: drop an UpdatePanel onto a page, place some controls inside it, register a ScriptManager somewhere on the page, and the framework would intercept postbacks originating from controls inside the panel and turn them into asynchronous XMLHttpRequests that returned just the rendered HTML of the panel itself. The browser swapped that HTML into the page in place of the existing panel content, and the user saw a partial update instead of a full reload.
The minimal example looked roughly like this:
aspx
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:UpdatePanel ID="OrdersPanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:GridView ID="gridOrders" runat="server" />
<asp:Button ID="btnRefresh" runat="server"
Text="Refresh"
OnClick="btnRefresh_Click" />
</ContentTemplate>
</asp:UpdatePanel>csharp
protected void btnRefresh_Click(object sender, EventArgs e)
{
gridOrders.DataSource = _orderService.GetRecentOrders();
gridOrders.DataBind();
// Only OrdersPanel re-renders; the rest of the page stays untouched.
}The developer wrote what looked like an ordinary WebForms event handler. The framework arranged the asynchronous transport, the partial render, and the swap. No JavaScript was authored. No XHR was written by hand. The same code worked synchronously and asynchronously depending on whether the panel intercepted the postback. For internal applications, line-of-business tools, and most of the CRUD that powered the early-2000s enterprise web, it was remarkably effective.
What HTMX is doing now
The HTMX version of the same idea takes a completely different implementation route to a near-identical architectural shape. Instead of server controls, a ScriptManager, and a postback model, HTMX extends HTML itself with a handful of attributes — hx-get, hx-post, hx-target, hx-swap, hx-trigger — that tell the browser, declaratively, to issue an AJAX request when an element is interacted with and to swap the response into a target element on the page. The server returns plain HTML fragments. The client requires no build step. There is no state management library, no virtual DOM, no hydration phase.
The minimal example, written against any backend that can return HTML, looks like this:
html
<div id="orders">
<!-- Rendered server-side from the initial request -->
<table>
<tr><td>1001</td><td>Atelier Co.</td><td>£420</td></tr>
<tr><td>1002</td><td>Bridge Studio</td><td>£180</td></tr>
</table>
</div>
<button hx-get="/orders/recent"
hx-target="#orders"
hx-swap="innerHTML">
Refresh
</button>When the button is clicked, the browser issues a GET /orders/recent, the server returns an HTML fragment containing the updated table, and HTMX replaces the contents of #orders with it. The server can be ASP.NET Core, Django, Rails, Go, Phoenix, or a shell script — HTMX does not care. The pattern is described entirely in the HTML, and the page is server-rendered both initially and on every update.
If you take a step back from the syntax, the architectural decision is identical to what UpdatePanel made. Both put canonical state on the server. Both send HTML over the wire on update. Both swap a target region on the client. Both deliberately avoid the complexity of maintaining a parallel client-side state graph. The pattern has not changed. The packaging has.
Why UpdatePanel got a bad reputation and HTMX did not
Here is the interesting question. If the architectural pattern is the same, and the same pattern is now being celebrated by a generation of developers who would have refused to touch UpdatePanel, what changed?
Three things, principally.
The first is that UpdatePanel was inextricable from ViewState. Every partial postback through an UpdatePanel still ran the full WebForms page lifecycle on the server: Init, Load, event handling, render, and the serialization of ViewState back into the response. The panel was clever about sending only its own rendered output to the browser, but the round-trip on the wire still included the full ViewState payload of every control on the page, going both directions, on every "partial" update. For a non-trivial page, the partial update was not actually all that partial in network terms. HTMX, by contrast, sends nothing extraneous. The request is a normal HTTP request; the response is the HTML fragment and nothing else. The pattern's promise of "less data on the wire" was achievable in HTMX in a way that the WebForms implementation made structurally hard.
The second is that UpdatePanel was tied to a framework — ASP.NET WebForms — that had become the symbol, fairly or unfairly, of everything the next generation of developers wanted to leave behind. The pattern was guilty by association with server controls, with the postback model, with code-behind, and with the design choices that had made WebForms feel old by the early 2010s. HTMX is framework-agnostic by design. It does not pull in a server-side ecosystem; it sits on top of whatever the developer already uses. That neutrality is part of why it has been adopted across communities that share almost nothing else in common.
The third, and probably most important, is the level of abstraction. UpdatePanel hid the asynchronous machinery completely. A developer could use it without ever understanding that XMLHttpRequests were being issued or that HTML fragments were being swapped. That was the point, and at the time it was a strength. With twenty years of hindsight, it is also a weakness — the hiding made it impossible to reason about what was happening on the wire, what the cost of an update actually was, or how to optimize it. HTMX, by contrast, exposes the entire mechanism through HTML attributes that a developer can read. The asynchronous behaviour is visible on the page that triggers it. The level of abstraction is lower, and the lower abstraction turns out to be both easier to learn and easier to debug.
What HTMX learned, even when it did not name the lesson
The most useful way to read HTMX, for a developer who lived through the WebForms era, is as the WebForms pattern with the structural problems removed. Hypermedia as a system. HTML over the wire. Server-rendered partials. The right level of abstraction. All of it was being argued for, implicitly, by the design of UpdatePanel. The argument was discredited partly by the implementation cost and partly by the era it belonged to. The argument itself was sound, and HTMX is the version of it that works under modern conditions.
There is a broader point hiding in the comparison. The web spent more than a decade convinced that client-side state management was the future, that the SPA was the natural endpoint of UI development, and that anyone advocating for server-rendered HTML had failed to understand the inevitability of the move to React. The current shift — toward HTMX, toward Phoenix LiveView, toward Blazor Server, toward Hotwire — is not a rejection of what came before so much as a rediscovery of what the earlier pattern was trying to say. The hypermedia approach was not wrong in 2007. It was wrong in its implementation. The architecture is, by current consensus, vindicated.
A practical bridge for teams maintaining WebForms
For development teams who still maintain a WebForms application and want to modernize incrementally without committing to a React rewrite, HTMX is one of the more underrated migration paths available. The reason is mechanical: HTMX needs nothing but HTML and a backend that can return HTML fragments. WebForms can return HTML fragments. You can render an .ascx user control to a string, return it from a handler, and swap it into the page with hx-get and hx-target — without changing the rest of the application's architecture.
A practical first step looks roughly like this. Replace the simplest UpdatePanel on the lowest-risk page with an HTMX swap that calls a tiny ASHX handler returning the rendered user control as HTML. You lose the ViewState round-trip on that interaction immediately. You gain a clean attribute-level description of the asynchronous behaviour. You preserve every other part of the application, including the controls, the data layer, and the rest of the page lifecycle. Repeat on the next-simplest panel, then the next, until the application's hot paths are using HTMX and the long-tail ones still run the original pattern. There is no migration "weekend" required. There is no parallel front-end stack to maintain. There is just an incremental retirement of a piece of the framework whose job HTMX can do more cleanly.
Twenty years after the original AJAX pattern shaped how a generation thought about partial page updates, the same idea has come back under a different name, on a different stack, with the structural problems sanded off. The names changed. The architecture did not. For developers who lived through both, the most useful thing the moment offers is the recognition that the bet WebForms made about server-rendered partials was the correct bet — and that the path to validating it ran through a different implementation than the one the original framework provided.