Heimdall Docs

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 area

2. 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

1. The click triggers the server action.
2. The action returns an <invocation> targeting #toast-manager.
3. Heimdall.js consumes the instruction and inserts the toast into the layout region.

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 updates

10. 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.

Show a toast in the layout after a save.
Refresh a related list after a form submission.
Update a badge, counter, or status region elsewhere on the page.
Drive modal or shell-level UI from a local interaction.

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.