htmx Tutorial · Making Requests · Lesson 6 of 30
Triggers: hx-trigger
Choose which event sends the request: clicks, typing with a delay, page load, scrolling into view, keyboard filters and polling.
Default triggers
Without hx-trigger, htmx uses the natural event for each element:
| Element | Default trigger |
|---|---|
<input>, <textarea>, <select> |
change |
<form> |
submit |
| everything else | click |
Choosing the event
hx-trigger takes any DOM event name: hx-trigger="mouseenter", hx-trigger="keyup", hx-trigger="dblclick".
Separate several with commas: hx-trigger="click, keyup[key=='Enter']".
Modifiers
| Modifier | Meaning |
|---|---|
once |
trigger only the first time |
changed |
only if the element's value has changed |
delay:500ms |
wait until events stop for 500 ms, then send (debounce) |
throttle:1s |
send at most once per second |
from:<selector> |
listen for the event on another element, e.g. from:body |
<input name="q" placeholder="Type, then pause..." hx-get="/count" hx-target="#typed"
hx-trigger="input changed delay:500ms">
<p id="typed">Requests are sent only when you pause.</p>
<button hx-get="/once" hx-trigger="click once" hx-target="#once-out">Only works once</button>
<span id="once-out"></span>
<!-- The pretend server: on a real site this part is your backend (Python, PHP, Node, Go...) -->
<script>
server.get("/count", (req) => `You typed <strong>${server.escape(req.query.q)}</strong> (${(req.query.q || "").length} characters)`);
server.get("/once", () => "Done. Click again: nothing is sent.");
</script>
Special triggers
| Trigger | Fires |
|---|---|
load |
when the element is loaded into the page (lazy loading) |
revealed |
when the element scrolls into the viewport (infinite scroll) |
intersect |
like revealed, with options such as threshold:0.5 |
every 2s |
on a timer (polling) |
Events can also have a filter in square brackets, a JavaScript expression: keyup[key=='Enter'] or
click[ctrlKey].
<div hx-get="/news" hx-trigger="load">Loading the news...</div>
<p>Server time (updates every 2 seconds):
<strong hx-get="/clock" hx-trigger="load, every 2s">...</strong></p>
<input placeholder="Press Enter to send" name="msg" hx-post="/send" hx-trigger="keyup[key=='Enter']" hx-target="#sent">
<p id="sent"></p>
<!-- The pretend server: on a real site this part is your backend (Python, PHP, Node, Go...) -->
<script>
server.get("/news", () => "<p><strong>News:</strong> htmx 2.0.11 is out.</p>", { delay: 800 });
server.get("/clock", () => new Date().toLocaleTimeString());
server.post("/send", (req) => "Sent: " + server.escape(req.body.msg));
</script>
Test yourself
Which hx-trigger value sends a search request only after the user stops typing for half a second?
input changed delay:500msinput throttle:500msevery 500msload delay:500ms
Show answer
Answer: input changed delay:500ms
delay waits until events stop (debounce); changed skips requests when the value is the same.