Out-of-Band Updates
Out-of-band updates let a server response modify UI regions other than the primary target. Heimdall does this with a special <invocation> element that the client runtime consumes as an instruction rather than rendering directly.
This is one of Heimdall’s most important patterns because it lets one response update local UI, global layout UI, and related regions using HTML alone.
1. What Out-of-Band Means
Normally, an interaction returns HTML for its main target. Out-of-band updates extend that model by allowing the same response to also target other DOM regions.
Main response target:
- update the requested host
Out-of-band response:
- also update some other target
- such as a toast manager, notes list, modal region, or status area2. The Core Idea
Heimdall returns a special <invocation> element as part of the HTML response. The browser runtime reads it, applies its target and swap instructions, and does not render the invocation element itself.
<invocation
heimdall-content-target="#toast-manager"
heimdall-content-swap="afterbegin">
<div class="toast">Saved!</div>
</invocation>3. Strongly Typed Invocation Builder
In C#, you usually do not write raw invocation elements by hand. Instead, you use the strongly typed invocation builder.
HeimdallHtml.Invocation(
targetSelector: "#toast-manager",
swap: HeimdallHtml.Swap.AfterBegin,
payload: ToastManager.Create(toast),
wrapInTemplate: false
)4. Why This Is Powerful
Out-of-band updates let one action do more than one thing. A single server response can update the main target, refresh a related list, and show a toast in the layout.
return FluentHtml.Fragment(f =>
{
f.Add(GenerateForm(request, results));
f.Heimdall().Invocation(
targetSelector: "#notes-host",
swap: HeimdallHtml.Swap.Inner,
payload: RenderNotesList()
);
f.Heimdall().Invocation(
targetSelector: "#toast-manager",
swap: HeimdallHtml.Swap.AfterBegin,
payload: ToastManager.Create(toast)
);
});5. The Two Main OOB Shapes
In practice, out-of-band updates usually show up in two forms.
Pure OOB Response
The main response does not directly swap into a primary target. The returned HTML is only instructions for other regions.
- Often paired with SwapNone
- Good for toasts, layout regions, modal actions
- Useful when the interaction should not replace local content
Main Swap + OOB
The response updates the primary target and also includes extra invocation instructions for other regions.
- Very common for forms
- Lets one action refresh both local and global UI
- Great for form + list + toast workflows
6. Pure OOB Example
This pattern is used when the action should not directly update its initiating element. Instead, it returns an invocation that targets a known UI region.
Trigger
button.Heimdall()
.Click("OobPage.ToastHello")
.SwapNone();Action
[ContentInvocation]
public static Task<IHtmlContent> ToastHello()
{
var toast = new ToastItem
{
Header = "Hello from OOB!",
Content = "This toast came back as an <invocation> targeting #toast-manager.",
Type = ToastType.Success,
DurationMs = 1800
};
var html = ToastManager.Create(toast);
IHtmlContent result = FluentHtml.Fragment(f =>
{
f.Heimdall().Invocation(
targetSelector: "#toast-manager",
swap: HeimdallHtml.Swap.AfterBegin,
payload: html,
wrapInTemplate: false
);
});
return Task.FromResult(result);
}What Happens
7. Main Swap + OOB Example
This is one of the most useful patterns in Heimdall. The main response updates the primary host, and extra invocations update related regions.
return FluentHtml.Fragment(f =>
{
// Main content for the target
f.Add(GenerateForm(noteRequest, results));
// Also refresh the related list
f.Heimdall().Invocation(
targetSelector: "#notes-host",
swap: HeimdallHtml.Swap.Inner,
payload: RenderNotesList(),
wrapInTemplate: false
);
// Also show a toast
f.Heimdall().Invocation(
targetSelector: "#toast-manager",
swap: HeimdallHtml.Swap.AfterBegin,
payload: ToastManager.Create(toast),
wrapInTemplate: false
);
});This is a strong pattern for forms, editors, dashboards, and any workflow where one server action affects more than one UI boundary.
8. Layout-Level Targets
One of the most important out-of-band patterns is targeting regions that are rendered by the layout rather than the current page. Toast containers are the clearest example.
root.Id("toast-manager");
root.Add(
HeimdallHtml.SseTopic("toasts"),
HeimdallHtml.SseTarget("#toast-manager"),
HeimdallHtml.SseSwapMode(HeimdallHtml.Swap.BeforeEnd)
);9. OOB vs SSE
Out-of-band updates and SSE can solve similar UI problems, but they are not the same thing.
OOB Invocation:
- comes back in the current action response
- immediate result of a user interaction
- great for targeted side-effects
SSE / Bifrost:
- arrives over a live subscription
- can be triggered by other server activity
- great for real-time broadcast or async updates10. Invocation Payload and Template Wrapping
Most payload HTML can be emitted directly inside an invocation. But some fragments, especially table rows, may need template wrapping so the browser preserves them correctly during parsing.
HeimdallHtml.Invocation(
targetSelector: "#orders-table-body",
swap: HeimdallHtml.Swap.BeforeEnd,
payload: RenderRow(order),
wrapInTemplate: true
);11. Security and Runtime Behavior
Invocation elements are instructions, not normal rendered content. The runtime treats them specially. Script tags are stripped, and invocation targets can be restricted by configuration.
<invocation
heimdall-content-target="#some-target"
heimdall-content-swap="inner">
...
</invocation>12. When to Reach for OOB
Out-of-band updates are especially useful when an interaction should have side effects outside its main target.
13. What OOB Is Not
Out-of-band updates are not a different response protocol and not a client-side component event system. They are still HTML returned by the server, just with explicit instructions for non-primary targets.
The response is still HTML.
The server is still in control.
Heimdall.js just applies the instructions.Next Steps
Once out-of-band updates click, SSE and lazy loading become much easier to reason about.