import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
For over a decade, Drupal developers have relied on Drupal.ajax — a powerful but heavy abstraction layer over jQuery — to handle dynamic interactions. With jQuery's slow sunset and the rise of "HTML-over-the-wire" paradigms, the HTMX in Drupal Core initiative is the most sensible thing to happen to Drupal's frontend in years.
I built a proof-of-concept module to test what this migration actually looks like in practice.
The Problem with Drupal.ajax
"The server returns a JSON array of commands (
insert,remove,invoke), which the client must parse and execute."— Drupal Ajax Framework, Core Documentation
ℹ️ Info: Context
Drupal's Ajax system was built when jQuery was the only game in town and server-rendered HTML was unfashionable. The framework sends a proprietary JSON command protocol from PHP to JavaScript, which the client interprets and executes. Every other modern framework has moved past this pattern.
| Problem | Impact |
|---|---|
| Proprietary JSON command protocol | Developers must learn Drupal-specific API instead of web standards |
| Tight jQuery coupling | Blocks migration to modern JS |
| Client-side command runner | Complexity that HTMX eliminates entirely |
| Heavy payload | JSON commands instead of plain HTML fragments |
The HTMX Solution
HTMX offers a simpler, declarative model. You define interactions in HTML attributes, and the server returns HTML fragments. No custom JSON protocol. No complex client-side command runner.
Code Comparison
Here is how a simple "Get Server Time" feature looks in both paradigms.
The Controller
```php title="src/Controller/HtmxDemoController.php"
public function time() {
$time = $this->time->getCurrentTime();
$formatted = $this->dateFormatter->format($time, 'long');
// highlight-next-line
// Just return HTML. Simpler, lighter.
return new Response("
}
</TabItem>
<TabItem value="ajax" label="Drupal Ajax (Old)">
```php title="src/Controller/AjaxDemoController.php" showLineNumbers
public function timeAjax() {
$time = $this->time->getCurrentTime();
$formatted = $this->dateFormatter->format($time, 'long');
// highlight-next-line
// Construct a JSON response with commands.
$response = new AjaxResponse();
$response->addCommand(new HtmlCommand('#time-container', "<div>Time: $formatted</div>"));
return $response;
}
The Frontend
```html title="templates/htmx-demo.html.twig"
hx-target="#container"
hx-swap="innerHTML">
Get Time
</TabItem>
<TabItem value="ajax" label="Drupal Ajax (Old)">
```html title="templates/ajax-demo.html.twig"
<!-- Requires 'use-ajax' class and implicit conventions -->
<a href="/htmx-demo/time-ajax" class="use-ajax">
Get Time
</a>
Side-by-Side Comparison
| Aspect | Drupal Ajax | HTMX |
|---|---|---|
| Server response | Proprietary JSON commands | Standard HTML fragments |
| Client library | jQuery + drupal.ajax | htmx.js (~14KB) |
| Learning curve | Drupal-specific API | HTML attributes (web standard) |
| JS knowledge needed | Must understand AjaxCommand API | Minimal to none |
| Backend approach | Build AjaxResponse with commands | Return HTML string or render array |
| Debugging | Inspect JSON command array | Inspect HTML response in Network tab |
| Framework coupling | Drupal-only | Framework-agnostic |
quadrantChart
title HTMX vs Drupal Ajax: Effort vs Developer Experience
x-axis Low Effort --> High Effort
y-axis Poor DX --> Great DX
HTMX Controller: [0.25, 0.85]
HTMX Frontend: [0.2, 0.9]
Ajax Controller: [0.6, 0.4]
Ajax Frontend: [0.7, 0.35]
Ajax Debugging: [0.8, 0.2]
HTMX Debugging: [0.3, 0.8]
⚠️ Caution: Reality Check
Full core replacement is a massive undertaking. Drupal's Ajax system is deeply embedded in Form API, Views, field widgets, and dozens of contrib modules. The benefits of HTMX are clear, but the migration path will take years and involve painful backward-compatibility work. Do not expect to rip out
drupal.ajaxfrom your contrib modules next quarter.
Why This Matters
Who benefits and how
-
Frontend devs don't need to learn the
AjaxCommandPHP API. - Backend devs can return standard render arrays or templates.
-
Performance improves by removing the jQuery and
drupal.ajaxoverhead. - New contributors face a lower barrier to entry — HTMX is HTML, not a Drupal-specific protocol.
- The Drupal ecosystem aligns with the broader web ecosystem, making it more accessible to developers coming from other frameworks.
The Code
Why this matters for Drupal and WordPress
For Drupal module developers, HTMX adoption in core means rewriting Ajax-heavy contrib modules to return HTML fragments instead of JSON command arrays — starting with custom form widgets, Views exposed filters, and admin UI interactions. WordPress developers already familiar with HTMX through plugins like flavor or admin-ajax alternatives will find that Drupal's move validates the HTML-over-the-wire pattern at CMS-core level, making cross-CMS frontend skills more transferable. Agencies maintaining both Drupal and WordPress sites benefit from a converging frontend model where server-rendered HTML replaces framework-specific JavaScript abstractions.
What I Learned
- HTMX is a natural fit for Drupal's server-rendered philosophy. The paradigm match is almost too perfect.
- The migration from Ajax to HTMX is straightforward for new features. Retrofitting existing Ajax-heavy modules is where the real work lives.
- Removing the JSON command protocol eliminates an entire category of Drupal-specific knowledge that new developers currently have to learn.
- This initiative deserves more attention and contributor effort than it is currently getting.
References
Looking for an Architect who doesn't just write code, but builds the AI systems that multiply your team's output? View my enterprise CMS case studies at victorjimenezdev.github.io or connect with me on LinkedIn.
Looking for an Architect who doesn't just write code, but builds the AI systems that multiply your team's output? View my enterprise CMS case studies at victorjimenezdev.github.io or connect with me on LinkedIn.
Originally published at VictorStack AI — Drupal & WordPress Reference
Top comments (0)