API reference
Every component parameter, service member, option and value type, with its default -
the page to keep open while you write code. The topic pages explain why; this one
answers what it's called.
Everything below lives in the Bit.Brouter namespace. Add
@using Bit.Brouter to _Imports.razor once and none of it needs
qualifying.
Components
<Brouter> - the router
One per app, usually in App.razor or a dedicated AppRouter.razor.
Routes go in <Routes> (or directly as child content - the two are
aliases; never use both).
| Parameter | Type | Purpose |
| Routes / ChildContent | RenderFragment? | The route tree. Aliases of each other. |
| AppAssembly | Assembly? | Assembly to scan for @page / [Route] components. |
| AdditionalAssemblies | IEnumerable<Assembly>? | Further assemblies to scan (Razor class libraries, lazily-loaded ones). |
| OnNavigateAsync | Func<ctx, ValueTask<IEnumerable<Assembly>?>>? | Lazy route loading; returned assemblies register within the same navigation. |
| NotFoundUrl | string? | Redirect target when nothing matches. |
| NotFound | RenderFragment<BrouterLocation>? | Rendered in place instead, leaving the URL alone. |
| Navigating | RenderFragment? | Pending UI while loaders run; revealed lazily, so fast navigations never flash it. |
| ErrorContent | RenderFragment<BrouterErrorContext>? | Router-level error boundary - the last resort under every route's own. |
| ParallelLoaders | bool (false) | Run a chain's loaders concurrently instead of root → leaf sequentially. |
| Found | RenderFragment<RouteData>? | The built-in Router's template, ported verbatim. Applies to Component-rendered routes. |
| DefaultLayout | Type? | Layout for pages without their own @layout. |
| NotAuthorized | RenderFragment<AuthenticationState>? | Setting this (or Authorizing/Resource) routes through the framework's AuthorizeRouteView. |
| Authorizing | RenderFragment? | Shown while an authorization policy is being evaluated. |
| Resource | object? | Resource passed to resource-based authorization policies. |
| OnMatch | Func<Broute, ValueTask>? | Fired when a route matched, just before OnNavigated. |
| OnNotFound | Func<BrouterLocation, ValueTask>? | Fired when nothing matched. |
<Broute> - one route
Routes are components, so nesting is just markup: a <Broute> inside
another inherits its parent's template as a prefix. Render either a
Component or a Content fragment - not both.
| Parameter | Type | Purpose |
| Path (required) | string | The route template. Empty string on a child = the index route (matches the parent exactly). |
| Component | Type? | Component type to render; route values bind to its [Parameter] properties by name. |
| Content | RenderFragment<BrouterRouteParameters>? | Inline markup instead; the context argument is the parameter bag. |
| Routes / ChildContent | RenderFragment? | Child routes. Use Routes when the parent also has Content. |
| Name | string? | Enables NavigateToName/ResolveUrl and names the generated URL builder. |
| RedirectTo | string? | Redirect instead of rendering. Guards on the route still run first. |
| Group | bool (false) | Pathless group: contributes no URL segments, only shared guard/loader/layout/error boundary. |
| Guard | Func<ctx, ValueTask>? | Enter guard; runs root → leaf before the URL commits. |
| LeaveGuard | Func<ctx, ValueTask>? | Leave guard; runs leaf → root, only for routes actually being deactivated. |
| Loader | Func<ctx, ValueTask<object?>>? | Async data fetch; the result cascades as BrouterRouteData. |
| StaleTime | TimeSpan? | Freshness window for this route's loader results. Falls back to DefaultLoaderStaleTime. |
| Meta | object? | Static per-route metadata, cascaded as BrouterRouteMeta. No code runs. |
| KeepAlive | bool (false) | Retain the rendered component (hidden) when navigated away. |
| KeepAliveMax | int? | Retained-instance budget. Above 1, one instance per distinct parameter set, LRU-evicted. Defaults to DefaultKeepAliveMax. |
| ErrorContent | RenderFragment<BrouterErrorContext>? | Error boundary for this route and its descendants; nearest boundary wins. |
<BrouterLink> - navigation links
Renders a real <a>: Ctrl/middle/Shift clicks keep native browser
behavior, only plain left clicks are intercepted. Extra attributes are splatted onto the
anchor.
| Parameter | Type (default) | Purpose |
| Href (required) | string ("/") | Destination. Route-relative forms (./x, ../x) re-resolve after every navigation. |
| Match | BrouterLinkMatch (Prefix) | Active detection. Prefix is segment-boundary aware; All is exact. Root / always matches exactly. |
| ActiveClass | string ("active") | Class added when active; also sets aria-current="page". |
| Class | string? | Base class list, always applied. |
| Replace | bool (false) | Replace the current history entry instead of pushing. |
| Preload | BrouterLinkPreload? | Warm the loader cache before the click. Falls back to DefaultLinkPreload. |
| HistoryState | string? | State attached to the history entry this click creates. |
Outlets, views & deferred data
| Component | Parameters | Purpose |
| <BrouterOutlet> | Name (string, "") | Placed in a parent's content to mark where matched children render. A name creates a secondary region. |
| <BrouterView> | Name, ChildContent | Declared inside a child route's <Routes> to fill the same-named outlet of an ancestor. |
| <BrouterAwait<T>> | Task (required), Pending, Resolved, Error | Renders an unawaited Task<T> returned by a loader as it resolves. |
IBrouter - the service
Methods
Inject anywhere with @inject IBrouter brouter. Every URL argument accepts
route-relative forms.
| Member | Notes |
| Location | BrouterLocation for the current URL. Never null. |
| Navigate(url, replace, forceLoad, historyState) | Fire-and-forget. forceLoad does a full document load and skips the pipeline entirely. |
| NavigateAsync(url, replace, historyState) | Awaits the whole pipeline and returns a BrouterNavigationOutcome. No forceLoad - nothing would survive to resolve the task. |
| Back() / BackAsync(delta = 1) | Move back; the async form is awaitable and can jump several entries. |
| Forward() / ForwardAsync(delta = 1) | The forward equivalents. |
| NavigateToName(name, parameters, query, replace, historyState) | Target a Named route. Parameters not in the template become query pairs. |
| ResolveUrl(name, parameters, query) | The same substitution, returned as a string instead of navigated to. |
| NavigateWithQuery(mutate, replace = true) | Functional query update over a BrouterQueryBuilder; untouched parameters and the fragment survive. |
| RevalidateAsync() | Re-runs the current chain's loaders in place. No URL change, no guards, content stays visible. |
| ReloadAsync() | Rebuilds the current chain: components disposed and recreated, route guards and loaders re-run. No URL change, no navigation hooks, no leave guards. Loaders can tell a reload apart via BrouterNavigationContext.IsReload. Re-navigating to the same URL cannot do this - Blazor keeps the component. |
| PreloadAsync(url) | Speculatively runs the destination's loaders. No guards, no render, failures swallowed. |
| ClearLoaderCache() | Drops every cached loader result - e.g. on sign-out. |
| ClearKeepAlive() | Disposes every retained keep-alive component. The visible page keeps its instance. |
| ClearKeepAlive(includeActive) | With includeActive: true the page on screen is disposed and rebuilt in place too - fresh instance, no navigation, no guards or loaders re-run. |
| SetConfirmExternalNavigationAsync(enabled) | Arms/disarms the browser's "leave site?" dialog at runtime. Idempotent. |
Events
All three are async delegates. Subscribe in OnInitialized and
unsubscribe in Dispose - a forgotten handler keeps its component alive for the
router's lifetime.
| Event | Signature | Fires |
| OnNavigating | Func<ctx, ValueTask> | Before every navigation, after leave guards. Can Cancel() / Redirect(). |
| OnNavigated | Func<ctx, ValueTask> | After a navigation commits and renders. |
| OnError | Func<ctx, Exception?, ValueTask> | On unhandled pipeline exceptions. Cancels and redirects are control flow and never raise it. |
@inject IBrouter brouter
@implements IDisposable
@code {
private Func<BrouterNavigationContext, ValueTask>? _handler;
protected override void OnInitialized()
{
_handler = ctx => { Track(ctx.To.Path); return ValueTask.CompletedTask; };
brouter.OnNavigated += _handler;
}
public void Dispose()
{
if (_handler is not null) brouter.OnNavigated -= _handler;
}
}
BrouterOptions
Matching
| Option | Default | Effect |
| CaseSensitive | false | Whether literal segments match case-sensitively. |
| IgnoreTrailingSlash | true | Treat /users and /users/ as the same path. |
| Constraints | empty registry | Custom constraints, scoped to this DI container: o.Constraints.Register("slug", ...). |
Scroll & focus
| Option | Default | Effect |
| ScrollBehavior | None | ToTop scrolls to the top of the page after each navigation. |
| ScrollToFragment | true | /docs#install scrolls #install into view and focuses it. Wins over everything else that navigation. |
| RestoreScrollPosition | false | Restore each page's scroll position on Back/Forward. Takes over history.scrollRestoration. |
| ScrollPositionStorage | Memory | Where those positions live. SessionStorage is the recommended upgrade. |
| FocusOnNavigateSelector | null | Move focus to this selector after navigation so assistive tech announces the new page. Try "h1". |
Data & caching
| Option | Default | Effect |
| DefaultLoaderStaleTime | null | App-wide freshness window for routes without their own StaleTime. Null = no caching. |
| StaleReloadMode | Background | How a stale hit is served: render cached data and refresh behind it, or Blocking to treat stale as a miss. |
| LoaderCacheGcTime | 30 min | Hard ceiling on how old a cached result may ever be. |
| MaxLoaderCacheEntries | 50 | Cache size cap; oldest-written entries evicted first. |
| DefaultLinkPreload | None | Preload mode for links that don't set their own. |
| PreloadDelay | 50 ms | How long the pointer must rest on a link before Intent preloading fires. |
| PreloadStaleTime | 30 s | How long a preloaded result stays usable on routes that don't otherwise cache. |
| PersistLoaderState | false | Carry prerender loader results into the interactive pass so they don't double-fetch. |
| LoaderStateTypeInfoResolver | null | Source-generated JSON context that makes the above trimming/AOT-safe. |
| DefaultKeepAliveMax | 1 | Retained-instance budget for keep-alive routes that don't set their own. |
Transitions & leaving the app
| Option | Default | Effect |
| ViewTransitions | false | Wrap each navigation's render in document.startViewTransition. |
| ViewTransitionDefaultAnimations | true | Ship the direction-aware glide/fade set. Lives in the bit-brouter CSS layer, so your own rules override it without !important. |
| ViewTransitionRespectReducedMotion | true | Swap motion for opacity crossfades under prefers-reduced-motion. Keep it on in production. |
| ConfirmExternalNavigation | false | Always-on beforeunload confirmation for tab close / reload / external links. For dynamic control use SetConfirmExternalNavigationAsync instead. |
Context & value types
BrouterNavigationContext
The single argument to every guard, loader and hook. Cancel() and
Redirect() are only honored in the decide phase - a loader's context is
informational.
| Member | Meaning |
| From / To | Source and destination BrouterLocation. |
| NavigationType | Push / Replace / Pop (Back/Forward). |
| CancellationToken | Fires when a newer navigation supersedes this one. Thread it through your async calls. |
| IsRevalidation / IsPreload / IsReload | Why this loader is running, when it isn't a plain navigation. IsReload is set while ReloadAsync() rebuilds the chain - the URL is unchanged and the components were disposed and recreated. |
| Route / Parameters | The matched route and its bound values (set once matching has run). |
| Cancel() / Redirect(url) | Stop the navigation, or send it elsewhere. |
| IsCancelled / RedirectUrl | What a previous step in the chain already decided. |
BrouterLocation
| Member | Meaning |
| FullUri / Path / Segments | The absolute URI, the path alone, and the path split into segments. |
| Query / QueryParams | The raw query string, and it parsed into a multi-value dictionary. |
| GetQuery(key) / GetQueryAll(key) | First value, or every value for repeated pairs (?tag=a&tag=b). |
| Hash | The fragment, including its #. |
| HistoryState | State attached to this history entry; survives Back/Forward. |
Parameters, data & metadata
| Type | How you get it | Members |
| BrouterRouteParameters |
[CascadingParameter(Name = "RouteParameters")], or the <Content Context="p"> argument |
this[key], Contains, Get<T>, TryGet<T>, GetOrDefault<T>. Keys are case-insensitive. |
| BrouterRouteData |
[CascadingParameter] - cascaded by type |
The Loader result: Value, HasValue, Get<T>, TryGet<T>, GetOrDefault<T>. |
| BrouterRouteMeta |
[CascadingParameter] |
The route's static Meta object, same accessors. No code runs to produce it. |
| RouteData (framework type) |
[CascadingParameter] |
The committed navigation's framework route data, or null on not-found. For breadcrumbs and telemetry. |
Outcomes, errors & query building
| Type | Members |
| BrouterNavigationOutcome |
Status, Succeeded, RedirectedTo, Exception. Returned by NavigateAsync. |
| BrouterErrorContext |
Exception, Location, RetryAsync(). The argument to every ErrorContent. |
| BrouterQueryBuilder |
Set (null removes), SetAll (multi-value), Remove, Clear, Get, Contains, ToQueryString. The argument to NavigateWithQuery; calls chain. |
Route lifecycle
IBrouterRoute
Implement it on a Component-rendered page and the router finds it
automatically. Every member has a no-op default, so override only what you need. Derive
from BrouterRouteBase instead to also get sync overloads, an
IsActive property and an automatic re-render after activation. For components
that aren't the route root, take the cascaded BrouterRouteContext and call
Register(this) / Unregister(this).
| Member | Argument | When |
| OnActivatedAsync | BrouterRouteActivation | Route became active. IsFirstActivation distinguishes a first visit from a keep-alive return. |
| OnRenavigatedAsync | BrouterRouteRenavigation | Same route re-committed with different parameters or query. Carries both locations. |
| OnDeactivatedAsync | BrouterRouteDeactivation | Route left. Reason is Hidden (keep-alive) or Disposing. |
| OnDeactivatingAsync | BrouterRouteDeactivatingContext | Before being left - awaited and cancellable. The component-level navigation lock. |
| OnRenavigatingAsync | BrouterRouteRenavigatingContext | Before re-committing with new parameters - the case a LeaveGuard can't see. |
Enums
Every enum, every value
| Enum | Values |
| BrouterNavigationStatus | Succeeded, Cancelled, Redirected, NotFound, Failed, Superseded |
| BrouterNavigationType | Push, Replace, Pop |
| BrouterLinkMatch | Prefix, All |
| BrouterLinkPreload | None, Intent, Viewport, Render |
| BrouterScrollMode | None, ToTop |
| BrouterScrollPositionStorage | Memory, SessionStorage, LocalStorage |
| BrouterStaleReloadMode | Background, Blocking |
| BrouterRouteDeactivationReason | Hidden, Disposing |
Built-in constraints
Type constraints - validate and convert
The parameter binds a real CLR value. In a chain, the last type constraint
decides the bound type.
| Token | Binds |
| int, long | int / long, invariant culture. |
| float, double, decimal | The matching numeric type, invariant culture. |
| bool | bool - true/false, case-insensitive. |
| guid | Guid, any standard format. |
| datetime | DateTime, invariant culture. |
Validation constraints - accept or reject
The value stays a string; these only gate the match.
| Token | Rule |
| alpha | ASCII letters only. |
| min(n) / max(n) / range(a,b) | Numeric bounds. |
| minlength(n) / maxlength(n) | Text-length bounds. |
| length(n) / length(a,b) | Exact length, or a length range. |
| regex(pattern) | Inline pattern, case-insensitive and invariant. |
| file / nonfile | Looks / doesn't look like a file name. nonfile is the classic static-asset filter. |