Request/Response Lifecycle
When to Use
You need to understand how HTMX requests flow through Drupal's render pipeline to debug issues or build custom integrations.
Steps
-
Request Initiated — User interacts with HTMX-enabled element (button click, form change, etc.)
-
Request Configuration (
htmx:configRequestevent) — JavaScript adds parameters: _wrapper_format=drupal_htmx(ifdata-hx-drupal-only-main-contentpresent)ajax_page_stateparameters for differential asset loading_triggering_element_namefromHX-Trigger-Nameheader
Reference: /core/misc/htmx/htmx-assets.js lines 39-62
-
Server Processing — Request routes to controller/form, Drupal detects HTMX via headers
-
Response Generation — Controller returns render array with HTMX attributes/headers applied via
Htmxclass -
Response Rendering —
HtmxRenderercreates minimal HTML response:<!doctype html> <html> <head> <meta name="robots" content="noindex"> <title>Page Title</title> <css-placeholder token="..."> <js-placeholder token="..."> </head> <body> <!-- Status messages --> <!-- Main content --> </body> </html>
Reference: /core/lib/Drupal/Core/Render/MainContent/HtmxRenderer.php lines 53-73
- Asset Loading (
htmx:beforeSwapevent) — JavaScript extracts and loads new CSS/JS files not already on page
Reference: /core/misc/htmx/htmx-assets.js lines 84-146
-
Content Swap — HTMX swaps content according to swap strategy (
outerHTML,innerHTML, etc.) -
Behaviors Attach (
htmx:drupal:loadevent) — Drupal behaviors run on new content
Reference: /core/misc/htmx/htmx-behaviors.js lines 14-16
Decision Points
| At this step... | If... | Then... |
|---|---|---|
| Request Configuration | Element has data-hx-drupal-only-main-content |
Add _wrapper_format=drupal_htmx to trigger HtmxRenderer |
| Server Processing | Route has _htmx_route: TRUE |
HtmxRenderer automatically invoked by HtmxContentViewSubscriber |
| Response Rendering | Request has _wrapper_format=drupal_htmx OR route has _htmx_route: TRUE |
HtmxRenderer creates minimal response instead of full page |
| Asset Loading | Response includes new CSS/JS | loadjs loads only files not in ajax_page_state.libraries |
Common Mistakes
- Not understanding
onlyMainContent()vs_htmx_route— Both trigger HtmxRenderer but through different mechanisms - Expecting full page HTML — HtmxRenderer returns minimal structure with noindex meta tag
- Not accounting for asset loading delay — Behaviors fire AFTER assets load, not immediately after swap
- Forgetting history cleanup —
htmx:beforeHistoryUpdateremoves wrapper_format from URLs
See Also
- Previous: HTMX vs AJAX Decision
- Next: Basic Setup
- Reference:
/core/lib/Drupal/Core/EventSubscriber/HtmxContentViewSubscriber.php— Handles_htmx_routeoption