htmx-development

Drupal 11.3+ HTMX implementation and AJAX migration guidance.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "htmx-development" with this command: npx skills add camoa/claude-skills/camoa-claude-skills-htmx-development

HTMX Development

Drupal 11.3+ HTMX implementation and AJAX migration guidance.

When to Use

  • Implementing dynamic content updates in Drupal

  • Building forms with dependent fields

  • Migrating existing AJAX to HTMX

  • Adding infinite scroll, load more, real-time validation

  • NOT for: Traditional AJAX maintenance (use ajax-reference.md)

Decision: HTMX vs AJAX

Choose HTMX Choose AJAX

New features Existing AJAX code

Declarative HTML preferred Complex command sequences

Returns HTML fragments Dialog commands needed

Progressive enhancement needed Contrib expects AJAX

Hybrid OK: Both systems coexist. Migrate incrementally.

Quick Start

  1. Basic HTMX Element

use Drupal\Core\Htmx\Htmx; use Drupal\Core\Url;

$build['button'] = [ '#type' => 'button', '#value' => t('Load'), ];

(new Htmx()) ->get(Url::fromRoute('my.content')) ->onlyMainContent() ->target('#result') ->swap('innerHTML') ->applyTo($build['button']);

  1. Controller Returns Render Array

public function content() { return ['#markup' => '<p>Content loaded</p>']; }

  1. Route (Optional HTMX-Only)

my.content: path: '/my/content' options: _htmx_route: TRUE # Always minimal response

Core Patterns

Pattern Selection

Use Case Pattern Key Methods

Dependent dropdown Form partial update select() , target() , swap('outerHTML')

Load more Append content swap('beforeend') , trigger('click')

Infinite scroll Auto-load swap('beforeend') , trigger('revealed')

Real-time validation Blur check trigger('focusout') , field update

Multi-step wizard URL-based steps pushUrl() , route parameters

Multiple updates OOB swap swapOob('outerHTML:#selector')

Dependent Dropdown

public function buildForm(array $form, FormStateInterface $form_state) { $form['category'] = ['#type' => 'select', '#options' => $this->getCategories()];

(new Htmx()) ->post(Url::fromRoute('<current>')) ->onlyMainContent() ->select('#edit-subcategory--wrapper') ->target('#edit-subcategory--wrapper') ->swap('outerHTML') ->applyTo($form['category']);

$form['subcategory'] = ['#type' => 'select', '#options' => []];

// Handle trigger if ($this->getHtmxTriggerName() === 'category') { $form['subcategory']['#options'] = $this->getSubcategories( $form_state->getValue('category') ); }

return $form; }

Reference: core/modules/config/src/Form/ConfigSingleExportForm.php

Multiple Element Updates

// Primary element updates via target // Secondary element updates via OOB (new Htmx()) ->swapOob('outerHTML:[data-secondary]') ->applyTo($form['secondary'], '#wrapper_attributes');

URL History

(new Htmx()) ->pushUrlHeader(Url::fromRoute('my.route', $params)) ->applyTo($form);

Htmx Class Reference

Request Methods

  • get(Url) / post(Url) / put(Url) / patch(Url) / delete(Url)

Control Methods

  • target(selector)

  • Where to swap

  • select(selector)

  • What to extract from response

  • swap(strategy)

  • How to swap (outerHTML, innerHTML, beforeend, etc.)

  • swapOob(selector)

  • Out-of-band updates

  • trigger(event)

  • When to trigger

  • vals(array)

  • Additional values

  • onlyMainContent()

  • Minimal response

Response Headers

  • pushUrlHeader(Url)

  • Update browser URL

  • redirectHeader(Url)

  • Full redirect

  • triggerHeader(event)

  • Fire client event

  • reswapHeader(strategy)

  • Change swap

  • retargetHeader(selector)

  • Change target

See: references/quick-reference.md for complete tables

Detecting HTMX Requests

In forms (trait included automatically):

if ($this->isHtmxRequest()) { $trigger = $this->getHtmxTriggerName(); }

In controllers (add trait):

use Drupal\Core\Htmx\HtmxRequestInfoTrait;

class MyController extends ControllerBase { use HtmxRequestInfoTrait; protected function getRequest() { return \Drupal::request(); } }

Migration from AJAX

Quick Conversion

AJAX HTMX

'#ajax' => ['callback' => '::cb']

(new Htmx())->post()->applyTo()

'wrapper' => 'id'

->target('#id')

return $form['element']

Logic in buildForm()

new AjaxResponse()

Return render array

ReplaceCommand

->swap('outerHTML')

HtmlCommand

->swap('innerHTML')

AppendCommand

->swap('beforeend')

MessageCommand

Auto-included

Migration Steps

  • Identify #ajax properties

  • Replace with Htmx class

  • Move callback logic to buildForm()

  • Use getHtmxTriggerName() for conditional logic

  • Replace AjaxResponse with render arrays

  • Test progressive enhancement

See: references/migration-patterns.md for detailed examples

Validation Checklist

When reviewing HTMX implementations:

  • Htmx class used (not raw attributes)

  • onlyMainContent() for minimal response

  • Proper swap strategy selected

  • OOB used for multiple updates

  • Trigger element detection works

  • Works without JavaScript (progressive)

  • Accessibility: aria-live for dynamic regions

  • URL updates for bookmarkable states

Common Issues

Problem Solution

Content not swapping Check target() selector exists

Wrong content extracted Check select() selector

JS not running Verify htmx:drupal:load fires

Form not submitting Check post() and URL

Multiple swaps fail Add swapOob('true') to elements

History broken Use pushUrlHeader()

References

Bundled (HTMX-Specific)

  • references/quick-reference.md

  • Command equivalents, method tables

  • references/htmx-implementation.md

  • Full Htmx class API, detection, JS

  • references/migration-patterns.md

  • 7 patterns with before/after code

  • references/ajax-reference.md

  • AJAX commands for understanding existing code

Online Dev-Guides (Drupal Domain)

For Drupal domain context when analyzing, recommending, or validating HTMX patterns, fetch the guide index:

Index: https://camoa.github.io/dev-guides/llms.txt

Likely relevant topics: forms, routing, js-development, render-api

Usage: WebFetch the index to discover available topics, then fetch specific topic pages for Drupal patterns when the bundled HTMX references don't cover the underlying Drupal concept.

Key Files in Drupal Core

  • core/lib/Drupal/Core/Htmx/Htmx.php

  • Main API

  • core/lib/Drupal/Core/Htmx/HtmxRequestInfoTrait.php

  • Request detection

  • core/lib/Drupal/Core/Render/MainContent/HtmxRenderer.php

  • Response renderer

  • core/modules/config/src/Form/ConfigSingleExportForm.php

  • Production example

  • core/modules/system/tests/modules/test_htmx/

  • Test examples

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

code-pattern-checker

No summary provided by upstream source.

Repository SourceNeeds Review
General

html-generator

No summary provided by upstream source.

Repository SourceNeeds Review
General

memory-manager

No summary provided by upstream source.

Repository SourceNeeds Review