Triggers, forms, and feedback
Choose a custom trigger
Request on load, visibility, input, a custom event, or a timed interval when the feature genuinely requires it.
Natural triggers cover clicks, changes, and submits. Some features need a request without any direct user action on the element: content that loads when scrolled into view, a status that refreshes on a timer, or a request started by another part of your code. hx-trigger handles all of these.
<section hx-get="/recommendations" hx-trigger="revealed">
Loading recommendations…
</section>
Use load when a fragment is required immediately after initialization. Use revealed when scrolling the window should lazy-load it. For an element inside an overflow container, use intersect so Intersection Observer detects visibility correctly. The placeholder text matters here: it is what people see until the trigger fires, so make it honest about what is coming.
Polling uses a timing declaration:
<div hx-get="/jobs/42/status" hx-trigger="every 5s">
Processing…
</div>
The server can return status 286 to stop HTMX polling when the job reaches a terminal state. Without that stop condition, finished jobs keep generating a request every five seconds for as long as the tab stays open. Still avoid polling when a user action, normal refresh, SSE extension, or WebSocket extension better matches the update model.
The most flexible option is a custom event, which keeps the HTTP behavior visible in markup:
<div hx-get="/notifications"
hx-trigger="notificationsChanged from:body"></div>
Another script or an HX-Trigger response header can emit notificationsChanged. Dispatching it from JavaScript is one line:
document.body.dispatchEvent(new Event('notificationsChanged'))
The from:body modifier tells HTMX to listen on the body instead of the element itself. This solves cases where no element event fits. A <select> where one specific option must load content is a classic example: options fire no events of their own, so a change handler dispatches a custom event on the body and the HTMX element reacts to it. The event connects features; the element still declares the route and response target.
When a custom trigger seems dead, check the wiring first: the event must be dispatched on the same element named in from:. Test it by dispatching the event from the DevTools console and watching the Network panel for the request.
Lesson completed