We overcomplicated the web. A button that loads content should not require a build step, a router, a state manager, and fifty kilobytes of JavaScript. HTMX proves that hypermedia — the architectural style that built the web — is still the right answer for most applications. It is not retro. It is correct.
The browser is already a hypermedia client. Stop fighting it.
HTMX extends HTML with a handful of attributes. hx-get fetches content. hx-target specifies where to put it. hx-swap controls how it is inserted. That is the entire mental model. No virtual DOM. No hydration. No client-side state that gets out of sync with the server. Just HTML over the wire, the way the web was designed to work.
<!-- Load comments when the button is clicked -->
<button hx-get="/comments/42"
hx-target="#comments-list"
hx-swap="beforeend"
hx-indicator=".spinner">
Load More Comments
</button>
<div id="comments-list">
<!-- Comments rendered server-side -->
</div>
<!-- The server returns HTML fragments, not JSON -->
<!-- No client-side templating needed -->The server-side rendering becomes your single source of truth. State lives in one place. The database is the state. The PHP script queries it and returns HTML. The browser displays it. When state changes, the server sends new HTML. There is no reconciliation, no diffing, no state synchronization nightmare.
<?php
// comments.php — returns HTML, not JSON
$postId = (int) $_GET['post_id'];
$offset = (int) ($_GET['offset'] ?? 0);
$comments = $db->query(
'SELECT * FROM comments WHERE post_id = ? ORDER BY created_at DESC LIMIT 10 OFFSET ?',
[$postId, $offset]
);
foreach ($comments as $comment): ?>
<article class="comment" id="comment-<?= $comment['id'] ?>">
<header>
<strong><?= htmlspecialchars($comment['author']) ?></strong>
<time><?= date('M j, Y', strtotime($comment['created_at'])) ?></time>
</header>
<p><?= nl2br(htmlspecialchars($comment['body'])) ?></p>
</article>
<?php endforeach; ?>The criticism is predictable. But what about interactivity? What about real-time updates? What about offline support? These are fair questions. HTMX is not the answer to every problem. But it is the answer to most problems. For the edge cases, you sprinkle vanilla JavaScript where needed. The result is a fraction of the complexity, a fraction of the bundle size, and a fraction of the bugs.
I rebuilt a dashboard that previously ran on React and Next.js. The HTMX version has zero build steps, zero client-side state, and loads in under 100KB total. The React version was 1.2MB before images. The HTMX version is faster, more accessible, and easier to maintain. Sometimes the old way is the right way.
Comments