HTMX Events Overview
HTMX communicates with your page through a rich set of browser events. Every stage of an HTMX request — from the moment the trigger fires to the moment the content settles into the DOM — produces an event you can listen to and respond to. Understanding these events lets you build sophisticated behaviors, custom animations, error handling, and analytics integration without rewriting HTMX's core logic.
How HTMX Events Work
HTMX fires events on the element that triggered the request, and they bubble up through the DOM like any standard browser event. You listen for them with addEventListener in JavaScript, or with the hx-on attribute directly in HTML.
HTMX Request Lifecycle and Events:
[ User action triggers element ]
|
v
htmx:configRequest — add/modify headers or parameters
|
v
htmx:beforeRequest — cancel the request if needed
|
v
htmx:beforeSend — request leaves the browser
|
(server processing)
|
v
htmx:beforeSwap — inspect response before insertion
|
v
htmx:afterSwap — new content is in the DOM
|
v
htmx:afterSettle — CSS settle period complete
|
v
htmx:afterRequest — entire cycle finished
Complete Event Reference
| Event | When It Fires | Common Use |
|---|---|---|
| htmx:configRequest | Before the request is built | Add auth headers, CSRF tokens |
| htmx:beforeRequest | Just before sending | Cancel the request conditionally |
| htmx:beforeSend | Request is being sent | Show a loading overlay |
| htmx:afterRequest | Request completed (success or error) | Reset forms, hide spinners |
| htmx:beforeSwap | Before DOM update | Inspect or modify the response HTML |
| htmx:afterSwap | After DOM update | Re-initialize third-party widgets |
| htmx:afterSettle | After CSS settle delay | Trigger animations or focus management |
| htmx:responseError | Server returns 4xx or 5xx | Show error messages |
| htmx:sendError | Network failure (no response) | Show offline warning |
| htmx:timeout | Request timed out | Show retry prompt |
| htmx:confirm | hx-confirm triggers | Custom confirmation dialog |
| htmx:historyRestore | Browser back/forward used | Restore page state |
| htmx:load | New content loaded into DOM | Initialize scripts for new elements |
Listening to Events With JavaScript
<!-- Listen on a specific element -->
<script>
document.getElementById('my-btn').addEventListener('htmx:afterRequest', function(event) {
console.log('Request complete:', event.detail);
});
</script>
<!-- Listen globally on the document (catches all HTMX requests) -->
<script>
document.addEventListener('htmx:afterRequest', function(event) {
if (!event.detail.successful) {
alert('Something went wrong. Please try again.');
}
});
</script>
The event.detail Object
Every HTMX event passes a detail object with information about the request. The contents vary by event, but common fields include:
| Field | Type | Description |
|---|---|---|
| detail.elt | Element | The element that triggered the request |
| detail.xhr | XMLHttpRequest | The raw XHR object (access status, headers) |
| detail.target | Element | The target element being updated |
| detail.successful | Boolean | True if the response was 2xx |
| detail.failed | Boolean | True if the response was 4xx or 5xx |
| detail.requestConfig | Object | URL, method, headers, and body of the request |
Practical Example: Global Error Handler
<div id="global-error" style="display:none; color:red; padding:10px; background:#ffe0e0">
An error occurred. Please try again.
</div>
<script>
document.addEventListener('htmx:responseError', function(event) {
const errDiv = document.getElementById('global-error');
errDiv.style.display = 'block';
setTimeout(() => errDiv.style.display = 'none', 5000);
});
document.addEventListener('htmx:sendError', function() {
alert('Network error. Check your connection and try again.');
});
</script>
Practical Example: Adding a CSRF Token to Every Request
<script>
document.addEventListener('htmx:configRequest', function(event) {
event.detail.headers['X-CSRFToken'] = document.cookie
.split('; ')
.find(row => row.startsWith('csrftoken='))
?.split('=')[1];
});
</script>
This single listener adds the CSRF token to every HTMX request on the page. You write it once and never think about it again.
Cancelling a Request With htmx:beforeRequest
<script>
document.getElementById('save-btn').addEventListener('htmx:beforeRequest', function(event) {
const title = document.getElementById('title-input').value.trim();
if (!title) {
event.preventDefault(); // Cancel the HTMX request
alert('Title cannot be empty.');
}
});
</script>
Calling event.preventDefault() inside htmx:beforeRequest stops the request entirely. The server is never contacted.
Key Takeaway
HTMX fires events at every stage of the request lifecycle. Listen to htmx:afterRequest for post-submit cleanup, htmx:responseError and htmx:sendError for error handling, htmx:configRequest to add global headers, and htmx:beforeRequest to cancel requests conditionally. The event.detail object gives you full access to the request context. These events are the bridge between HTMX's automatic behavior and any custom logic your application needs.
