Review: HTMX in Drupal Core and the Ajax API Replacement
For over a decade, Drupal developers have relied on Drupal.ajax—a powerful but heavy abstraction layer over jQuery—to handle dynamic interactions. But with jQuery's slow sunset and the rise of "HTML-over-the-wire" paradigms, it's time for a change.
Enter the HTMX in Drupal Core initiative.
The Problem with Drupal.ajax
Drupal 7 introduced the Ajax framework to allow developers to modify the DOM from PHP without writing JavaScript. It was revolutionary. But it came with a cost:
- Complexity: The server returns a JSON array of commands (
insert,remove,invoke), which the client must parse and execute. - Dependency: It is tightly coupled to jQuery.
- Performance: The payload is proprietary JSON, not standard HTML.
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.
I built a proof-of-concept module, drupal-htmx-ajax-replacement-demo, to explore what this migration looks like in practice.
Code Comparison
Here is how a simple "Get Server Time" feature looks in both paradigms.
1. The Controller
In the legacy approach, we construct an AjaxResponse with commands. In HTMX, we just return a string (or a render array).
- HTMX (New)
- Drupal Ajax (Old)
public function time() {
$time = $this->time->getCurrentTime();
$formatted = $this->dateFormatter->format($time, 'long');
// Just return HTML. Simpler, lighter.
return new Response("<div>Time: $formatted</div>");
}
public function timeAjax() {
$time = $this->time->getCurrentTime();
$formatted = $this->dateFormatter->format($time, 'long');
// Construct a JSON response with commands.
$response = new AjaxResponse();
$response->addCommand(new HtmlCommand('#time-container', "<div>Time: $formatted</div>"));
return $response;
}
2. The Frontend
In the template, HTMX replaces the need for the use-ajax class and the heavy core/drupal.ajax library.
- HTMX (New)
- Drupal Ajax (Old)
<!-- Declarative: Get from URL, swap into target -->
<button hx-get="/htmx-demo/time"
hx-target="#container"
hx-swap="innerHTML">
Get Time
</button>
<!-- Requires 'use-ajax' class and implicit conventions -->
<a href="/htmx-demo/time-ajax" class="use-ajax">
Get Time
</a>
Why This Matters
This isn't just about swapping libraries. It's about reducing the cognitive load for Drupal developers.
- 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.
While full core replacement is a massive undertaking, the benefits of moving to a standard like HTMX are clear. It aligns Drupal with the broader web ecosystem, making it more accessible to new developers.
The Code
I've published the demo module so you can test the difference yourself.
View Code
