Heimdall Docs

JavaScript Runtime

Heimdall’s JavaScript runtime is the browser-side layer that interprets Heimdall behavior expressed in the DOM and turns it into server-driven HTML interactions.

It does not replace your server rendering model. It does not become your application state store. It simply makes HTML boundaries interactive.

1. What the JavaScript Runtime Is

The Heimdall runtime is the small browser-side layer that reads Heimdall attributes, listens for interaction boundaries, gathers payload, sends requests, and applies returned HTML back into the DOM.

DOM contains Heimdall behavior
-> runtime discovers it
-> trigger fires
-> payload is resolved
-> request is sent
-> HTML returns
-> swap is applied
-> new DOM is activated

2. What It Is Not

Heimdall.js is intentionally narrow. It is not a client-side component framework, not a virtual DOM, not a JSON API client layer, and not a browser-side state store.

Heimdall.js is not:
- a SPA framework
- a virtual DOM
- a component renderer
- a client-side app state container
- a replacement for your server UI

3. Why the Runtime Exists

Heimdall’s server model only works if the browser has a small execution layer that can interpret the behavior already rendered into the page. The runtime is that layer. It lets the DOM express interactions directly without forcing a second application architecture into the browser.

Server renders behavior into HTML
-> browser runtime interprets it
-> server returns next HTML truth

4. Adding Heimdall.js to a Project

Heimdall interactivity is not limited to the template app. If you are porting an existing project to use Heimdall for interaction, the runtime can be added to any server-rendered application where you want DOM-declared server actions.

That includes Heimdall pages, MVC views, Razor Pages, or even an application that also contains Blazor. The important point is that Heimdall only needs rendered HTML plus the runtime script.

Layout Include

<script src="/_content/HeimdallFramework.Web/heimdall.js"></script>

In practice, this is usually placed near the end of the shared layout so the runtime is available to all rendered pages that use Heimdall attributes.

Mental Model

Existing server-rendered app
+ heimdall.js
+ Heimdall attributes in rendered HTML
-> server-driven interactivity

5. Porting Heimdall into an Existing App

If you already have MVC, Razor Pages, or another server-rendered surface, Heimdall does not require you to rebuild the whole app. You can introduce it incrementally by adding the script, registering Heimdall on the server, and rendering Heimdall behavior only where you want richer server-driven interactions.

Start with one interactive boundary
-> add Heimdall behavior to that HTML
-> map an action
-> let the runtime handle the interaction

6. MVC, Razor Pages, and Blazor

Heimdall’s runtime is tied to HTML, not to one ASP.NET rendering style. That means you can use it inside a dedicated Heimdall app, an MVC app, a Razor Pages app, or alongside other technologies where a server-rendered boundary should become interactive.

MVC can render Heimdall-enabled HTML in views or partials.
Razor Pages can render Heimdall-enabled HTML in page markup.
Blazor can coexist in the same application, while Heimdall is used for boundaries where HTML-over-the-wire is the better fit.
The runtime only needs the script and the rendered Heimdall attributes to operate.

The architectural choice is not all-or-nothing. Heimdall can be introduced where server-driven DOM interaction is the clearest model.

7. Bootstrapping the DOM

When the page loads, the runtime scans the DOM for Heimdall behavior and activates supported boundaries. That includes triggers, polling, visibility observers, scroll observers, and other runtime-managed interaction points.

page loads
-> runtime scans DOM
-> Heimdall boundaries are activated
-> browser is ready to interpret interaction behavior

8. The Trigger Layer

The runtime listens for the interaction boundaries already described in the DOM. Those include click, submit, input, change, keydown, blur, hover, visible, scroll, and load.

Runtime-observed triggers:
- click
- submit
- input
- change
- keydown
- blur
- hover
- visible
- scroll
- load

9. Payload Resolution

Once an interaction starts, the runtime resolves the payload source. This can come from a nearby form boundary, a nearby state boundary, keyed state, self, an explicit selector, an inline object, or a referenced object path.

Common payload sources:
- closest-form
- closest-state
- closest-state:key
- self
- #selector
- heimdall-payload
- heimdall-payload-ref
- ref:Some.Object.Path

This is the runtime’s request-construction step. It resolves the browser-side request context before the server action runs.

10. Modifiers and Runtime Controls

The runtime also interprets modifier-style behavior that shapes invocation without changing the underlying interaction model. These include debounce, key filtering, hover delay, visible-once, scroll threshold, prevent-default, disable behavior, and polling.

Runtime controls shape:
- timing
- filtering
- request suppression
- in-flight behavior
- repeated invocation

11. Request Lifecycle

After trigger and payload resolution, the runtime performs the request using the behavior expressed on the element. It tracks in-flight work, applies built-in defaults such as prevent-default or disable behavior when appropriate, and waits for HTML to return.

trigger fires
-> payload resolved
-> request sent
-> response returns
-> HTML is processed

The important point is that the runtime is not trying to interpret domain state. It is only moving interaction state through the request-response cycle.

12. Swaps from the Browser Side

When HTML returns, the runtime resolves the target and applies the configured swap. Inner, outer, beforeend, afterbegin, and none are all browser-side application strategies for the returned HTML.

Response HTML
+ target
+ swap mode
-> browser applies the update

13. Out-of-Band Processing

The runtime also processes out-of-band updates in the same response. That allows one action response to update multiple DOM regions even though one primary interaction triggered the request.

main response arrives
-> primary swap is applied
-> OOB fragments are discovered
-> additional DOM regions are updated

14. Polling Lifecycle

Polling is also runtime-managed. The browser schedules repeated invocation for a DOM boundary, prevents overlap on the same boundary, respects document visibility, and stops when the boundary is removed from the DOM.

DOM boundary exists
+ poll interval
-> runtime invokes repeatedly
-> pauses when hidden
-> stops when disconnected

That makes polling a runtime lifecycle concern rather than a server-side loop or a hand-written client timer system.

15. SSE / Bifrost Integration

The runtime also participates in server-pushed HTML updates. In that model, the browser is no longer initiating a request for each update. Instead, the runtime receives pushed HTML and applies it into the current document according to the subscription and target rules already established.

SSE / Bifrost
-> server pushes HTML
-> runtime receives it
-> DOM is updated

16. Rebooting New HTML

One of the most important runtime responsibilities is that newly inserted HTML is not left inert. After swaps and other DOM updates, the runtime reprocesses new boundaries so that triggers, polling, and related behavior continue to work on the updated UI.

HTML swapped into DOM
-> runtime activates new Heimdall boundaries
-> interaction continues naturally

17. Why the Runtime Stays Small

Heimdall works best because the runtime does not try to own the application. It interprets, transports, updates, and reactivates behavior, but it does not become the source of truth for the UI.

Runtime owns:
- interpretation
- request execution
- DOM update application
- boundary activation

Server owns:
- UI decisions
- rendered HTML
- application truth

18. Common Mental Model

A good way to think about heimdall.js is that it is the browser-side execution layer for DOM-declared server interactions.

Server renders behavior into HTML
-> runtime interprets that behavior
-> runtime sends requests when needed
-> server returns next HTML truth
-> runtime applies it
-> updated DOM is activated again

19. Why This Matters Architecturally

The runtime completes Heimdall’s architectural loop. The DOM remains the interaction boundary. The server remains the source of truth. The browser remains a small, capable runtime rather than a second application competing with the first.

DOM = interaction boundary
Runtime = execution layer
Server = source of truth

Next Steps

Once the runtime model is clear, the next step is seeing how these pieces compose into larger interaction flows and then collecting the surface area into a concise reference.