Developer Docs - Mobile Docs - Triggers

By default, a Helix request fires on the element's natural interaction: a tap. Hx.Trigger changes that.








Events

Named events are looked up on the control itself, so what is available depends on what you put the trigger on.

Three ways a trigger quietly does the wrong thing

Unfocused on something that cannot take focus. Every visual element declares Unfocused, so it wires successfully on a Label or a VerticalStackLayout, and then never fires, because those never receive focus. Use it on Entry, Editor, SearchBar, Rock:TextBox, or Rock:Picker.

An event name that does not exist falls back to a tap. Hx.Trigger="TextChanged" on a Label is not an error. Helix does not find the event, so the element gets a tap gesture instead and your request still fires, just from the wrong interaction.

every, revealed, and intersect wire nothing at all. These are the exception to the tap fallback above, deliberately so: falling back to a surprise tap would be worse than doing nothing. An element with Hx.Trigger="revealed" is simply inert, with no error to tell you why, so do not reach for HTMX's polling or scroll-into-view idioms yet. See Limitations.

Modifiers

One of each, on a control that suits it:


Times accept 400ms, 2s, or a bare number of milliseconds. A time that cannot be parsed is dropped, leaving the trigger with no delay or throttle at all.

Modifiers stack. They always apply in the order once, changed, throttle, delay, no matter what order you write them in. The search example at the top of this page combines two: TextChanged changed delay:400ms waits for a pause in typing and skips the request when the text came back to what it already was.

A modifier is only a modifier when an event name comes first. Hx.Trigger="once" reads once as the event name, finds no such event on the control, and falls back to a tap that fires every single time. Write clicked once.

Unrecognized modifiers, including HTMX's from:, target:, consume, and queue, are parsed and ignored rather than treated as errors, so a template written for a newer shell degrades instead of failing.

changed needs a control with a readable value

changed compares against the same value mapping automatic value inclusion uses. On a control the app cannot read a value from, the current value and the last value are both empty, they compare equal, and the request never fires. No error, no warning.

Use changed only on:

See Forms and Values for the full mapping.

load fires once per element, ever

If you set Hx.Trigger="load" on an element that is already on screen, it fires immediately. But it will not fire again when the element re-attaches, for instance after the person pushes a detail page and comes back. When you need a refresh on return, that is what appear is for.

appear fires every time the page comes back

load answers "get this once." appear answers "keep this current." It hooks the page that contains the element and fires each time that page appears, which includes the first appearance, so it is a superset of load rather than an alternative to it.


The case it exists for: the person taps into a detail screen, changes something there, and comes back. With load the summary they return to is the one rendered before they left, and it is now wrong. With appear it re-fetches on the way back in.

Pair it with throttle when the screen is one people bounce in and out of, so a quick there-and-back does not fire a second request:

Four things to know:

appear is not revealed. appear is about the page coming into view; revealed is about the element scrolling into the viewport, and it is still not implemented. An element far down a long scroll fires its appear when the page opens, whether or not anyone has scrolled to it.

Adding once to it (appear once) collapses it back to load behavior: first appearance only. Write load instead, which says the same thing more plainly.

When a trigger fires

Four things about the order, because each one explains a symptom that otherwise looks inexplicable.

Resolution happens before any dialog. The verb, route, target, swap, and indicator are all resolved first. So if Hx.Target names an id that does not exist, you never see your Hx.Confirm prompt at all. You get the error notification instead, and it looks as though the confirmation was ignored.

Then the gates, in this order: Hx.Confirm, Hx.Prompt, a form submission's own validation, then Hx.Validator. Cancelling a dialog or failing a validator aborts before anything is sent.

A second tap while a request is in flight is dropped. This is per element, so it is real double-tap protection without locking the rest of the screen. You do not need to add your own.

Navigating away cancels whatever is in flight, including a pending delay, so a response can never arrive and swap into a screen that is gone.

For what happens once the response arrives, see Endpoint Responses.