navius

Server & WebAssembly

How Navius works across Blazor's hosting models, and why the accessibility behaviour lives in a JavaScript engine driven from C#.

Why an engine

Blazor can't synchronously touch the DOM. Under WebAssembly there is no DOM available to .NET directly; under Server, every DOM interaction is marshalled asynchronously over SignalR. A correct focus trap, scroll lock, anchored positioner, or roving tabindex therefore cannot be pure C#. Navius keeps that behaviour in a small ES module, navius-interop.js, and drives it from C# over JS interop. The module is served from the package's static assets at _content/Navius.Primitives/navius-interop.js and lazily import()ed on first use.

Hosting models

Because every interop call is already async, the same primitives work unchanged across WebAssembly, Server, Blazor Web App (per-component render modes), and MAUI Blazor. Register services once at startup:

Render modes

In a Blazor Web App, mark stateful primitives interactive so their event handlers and engine calls run. Static SSR is fine for purely presentational parts (Label, Separator, Aspect Ratio).

Prerendering

Engine work runs in OnAfterRenderAsync, after the element exists, so server prerender produces correct, accessible markup with no interop calls, and the behaviour attaches once the component becomes interactive on the client. Register AddNavius() on both the server and the client of a Web App so prerendered islands resolve their services.

Teardown

Every engine handle is IAsyncDisposable and releases its DOM listeners on dispose. When a Server circuit drops mid-teardown, the disconnected-interop exception is swallowed; the DOM (and its listeners) are gone with the circuit anyway, so disposal never throws on navigation.