Triggers
Triggers define when a Heimdall interaction begins. They are the browser-side start of the request, response, and swap cycle.
A trigger answers one question only: when should this element invoke the server?
1. What a Trigger Means in Heimdall
A trigger is the event boundary that starts an interaction. It does not define payload shape, response structure, or swap behavior by itself. It simply tells the runtime when to begin.
Trigger
-> payload is gathered
-> action is invoked
-> HTML is returned
-> swap is applied2. The Core Pattern
In Heimdall, triggers are always attached through the behavior layer. That keeps HTML structure and Heimdall interaction behavior conceptually separate.
button.Heimdall()
.Click("Counter.Increment")
.PayloadFromClosestState()
.SwapOuter();3. Why Triggers Matter
Heimdall interactions are built from small, explicit pieces. The trigger is the first of those pieces. It gives the browser a precise point at which server-driven UI should continue.
4. Click
The click trigger is the most common starting point. It is a natural fit for buttons, links, and small interaction surfaces that should invoke the server when selected.
Fluent C#
button.Heimdall()
.Click("Counter.Increment")
.PayloadFromClosestState()
.SwapOuter();Rendered HTML
<button
heimdall-content-click="Counter.Increment"
heimdall-payload-from="closest-state"
heimdall-content-swap="outer">
Increment
</button>5. Submit
Submit is the form-native trigger. It works especially well when the form itself is the payload boundary and when native browser validation should remain part of the interaction.
Fluent C#
form.Heimdall()
.OnSubmit("Contact.Submit")
.PayloadFromClosestForm()
.SwapNone();This is one of the clearest examples of Heimdall working with normal HTML rather than replacing it.
Rendered HTML
<form
heimdall-content-submit="Contact.Submit"
heimdall-payload-from="closest-form"
heimdall-content-swap="none">
...
</form>6. Input
The input trigger fires as the user types. It is useful for live search, server-driven suggestions, and immediate validation feedback.
Fluent C#
input.Heimdall()
.Input("Search.Query")
.PayloadFromClosestForm()
.Target("#search-results")
.SwapInner();Rendered HTML
<input
heimdall-content-input="Search.Query"
heimdall-payload-from="closest-form"
heimdall-content-target="#search-results"
heimdall-content-swap="inner">Because input can fire frequently, it is usually best reserved for interactions where continuous feedback is worth the extra request volume.
7. Change
The change trigger is lower-frequency than input. It is a good fit when the interaction should wait until a selection or value change is committed.
Fluent C#
select.Heimdall()
.Change("Reports.Filter")
.PayloadFromClosestForm()
.Target("#report-results")
.SwapInner();Rendered HTML
<select
heimdall-content-change="Reports.Filter"
heimdall-payload-from="closest-form"
heimdall-content-target="#report-results"
heimdall-content-swap="inner">
...
</select>This often works well for select elements, toggles, or filter controls where per-keystroke updates are unnecessary.
8. Keydown
The keydown trigger fires in response to keyboard input. It is useful when a keypress itself is the interaction boundary rather than a full field change or submit.
Fluent C#
input.Heimdall()
.KeyDown("Search.Accept")
.PayloadFromClosestForm()
.Target("#search-results")
.SwapInner();Rendered HTML
<input
heimdall-content-keydown="Search.Accept"
heimdall-payload-from="closest-form"
heimdall-content-target="#search-results"
heimdall-content-swap="inner">This is often useful for keyboard-driven UI, quick actions, or flows where specific keys should initiate a request.
9. Blur
The blur trigger fires when an element loses focus. It is a natural fit for validation or post-edit checks that should happen after the user leaves a field.
Fluent C#
input.Heimdall()
.Blur("Profile.ValidateDisplayName")
.PayloadFromClosestForm()
.Target("#display-name-validation")
.SwapInner();Rendered HTML
<input
heimdall-content-blur="Profile.ValidateDisplayName"
heimdall-payload-from="closest-form"
heimdall-content-target="#display-name-validation"
heimdall-content-swap="inner">This keeps feedback tied to the end of a field interaction rather than to every keystroke.
10. Hover
The hover trigger fires when an element is hovered. It can be useful for previews, hints, or secondary content that should appear only when the user pauses over a boundary.
Fluent C#
div.Heimdall()
.Hover("Products.Preview")
.PayloadFromClosestState("product")
.Target("#product-preview")
.SwapInner();Rendered HTML
<div
heimdall-content-hover="Products.Preview"
heimdall-payload-from="closest-state:product"
heimdall-content-target="#product-preview"
heimdall-content-swap="inner">
...
</div>Hover is best used intentionally, especially when preview content is valuable but should not be loaded up front.
11. Visible
The visible trigger fires when an element becomes visible in the viewport. This is the foundation of lazy loading and continuation-boundary patterns.
Fluent C#
sentinel.Heimdall()
.Visible("Weather.LoadMore")
.PayloadFromClosestState("weather")
.Target("#weather-sentinel")
.SwapOuter();Rendered HTML
<div
heimdall-content-visible="Weather.LoadMore"
heimdall-payload-from="closest-state:weather"
heimdall-content-target="#weather-sentinel"
heimdall-content-swap="outer">
...
</div>12. Scroll
The scroll trigger fires as a scroll boundary is reached. It is useful when interaction should be tied to scroll position rather than simple visibility.
Fluent C#
div.Heimdall()
.Scroll("Activity.LoadEarlier")
.PayloadFromClosestState("activity")
.Target("#activity-stream")
.SwapInner();Rendered HTML
<div
heimdall-content-scroll="Activity.LoadEarlier"
heimdall-payload-from="closest-state:activity"
heimdall-content-target="#activity-stream"
heimdall-content-swap="inner">
...
</div>This can be useful for feeds, activity timelines, or UI that should react to scrolling through a region.
13. Load
The load trigger fires when an element is loaded into the DOM. It is useful when content should be requested immediately as part of initial rendering, but still through the normal Heimdall action pipeline.
Fluent C#
div.Heimdall()
.Load("Dashboard.Summary")
.Target("#summary-panel")
.SwapInner();Rendered HTML
<div
heimdall-content-load="Dashboard.Summary"
heimdall-content-target="#summary-panel"
heimdall-content-swap="inner">
</div>This can be useful for panels, widgets, or deferred sections that should begin empty and hydrate through a standard action.
14. Document Visible
The document-visible trigger fires whenever the document transitions from hidden to visible, such as when a user returns to the tab. It does not fire during initial page boot; combine it with Load when both moments should refresh.
Fluent C#
dashboard.Heimdall()
.DocumentVisible("Dashboard.Refresh")
.PayloadEmptyObject()
.Target("#dashboard")
.SwapInner();Rendered HTML
<div
heimdall-content-document-visible="Dashboard.Refresh"
heimdall-payload="{}"
heimdall-content-target="#dashboard"
heimdall-content-swap="inner">
</div>15. Online
The online trigger fires when the browser reports that connectivity has returned. It is a signal to attempt a normal action; it does not guarantee that the application server is reachable.
Fluent C#
connectionPanel.Heimdall()
.Online("Connection.Restore")
.PayloadEmptyObject()
.Target("#connection-panel")
.SwapInner();Rendered HTML
<div
heimdall-content-online="Connection.Restore"
heimdall-payload="{}"
heimdall-content-target="#connection-panel"
heimdall-content-swap="inner">
</div>16. Offline Is a Client Event
Offline cannot honor the server-invocation trigger contract. Heimdall therefore emits a client-only document event and never makes or queues a request for it.
document.addEventListener("heimdall:offline", event => {
console.log(event.detail.online); // false
showOfflineBanner();
});17. Trigger Does Not Mean Behavior by Itself
A trigger does not fully describe an interaction. It only defines the moment the interaction begins. The rest still comes from payload binding, target selection, and swap rules.
Trigger = when
Payload = what data is sent
Target = where response lands
Swap = how response is applied18. Why Heimdall Keeps Triggers Explicit
Heimdall stays clear by making interaction boundaries visible in the markup. Instead of hiding behavior behind a large client abstraction, the DOM itself expresses what event starts the request.
19. When to Use Which Trigger
Each trigger fits a different interaction shape.
Click -> buttons, links, explicit actions
Submit -> forms, native validation, traditional submits
Input -> live search, instant validation, live suggestions
Change -> committed field updates, select controls, filters
Keydown -> keyboard-driven actions, key-based flows
Blur -> post-edit validation, field completion checks
Hover -> previews, hints, deferred secondary UI
Visible -> element visibility, lazy loading, continuation boundaries
DocumentVisible -> refresh when returning to a hidden tab
Online -> retry or refresh when browser connectivity returns
Scroll -> feed or timeline interaction tied to scroll position
Load -> deferred initial content, startup widgetsNext Steps
Once triggers are clear, the next questions are how trigger behavior can be refined and how repeated runtime-driven invocation fits into the model.