Blazor in .NET 10 Gets Circuit State Persistence, Passkeys, and a Declarative State Model
Circuit state persistence and the declarative state model remove two long-standing friction points for Blazor Server and auto-render-mode apps: losing in-progress work on disconnect and writing repetitive prerendering state code. Passkey support brings passwordless authentication into the default Identity stack without third-party libraries.
Blazor Web Apps can now persist user session state across long disconnections or deliberate circuit pauses, using far fewer server resources than keeping a live circuit. A new `[SupplyParameterFromPersistentComponentState]` attribute eliminates the manual `PersistentComponentState` plumbing previously required to carry state from prerendering into interactive components. ASP.NET Core Identity gains built-in WebAuthn/FIDO2 passkey support, and the Preview 6 template ships with ready-made passkey management and login.
Routing gets a dedicated `NotFoundPage` parameter on the `Router` component, `NavigationManager.NavigateTo` stops throwing `NavigationException` during static SSR, and same-page navigation no longer scrolls to the top. `QuickGrid` picks up a `RowClass` parameter for conditional row styling and a `HideColumnOptionsAsync` method. On the interop side, Blazor can now construct JavaScript objects and get/set properties directly through new `IJSRuntime` and `IJSInProcessRuntime` methods.
Under the hood, response streaming is on by default for `HttpClient` in WebAssembly, Blazor scripts ship as fingerprinted static web assets, and standalone WebAssembly apps can opt into client-side fingerprinting for JavaScript modules. The custom Blazor cache and `BlazorCacheBootResources` MSBuild property are gone, replaced by standard browser caching.
Circuit state persistence changes the cost model for Blazor Server: a paused session now costs a small fixed memory allocation rather than a live CPU-and-memory-consuming circuit, which makes aggressive circuit suspension viable in production.
The declarative state model and the new form validation both depend on source generators, and the validation feature explicitly requires model types in separate C# files because one source generator's output cannot yet feed another — a constraint that reveals the current compiler pipeline boundary.
Default-enabling response streaming in WebAssembly HttpClient is a breaking change for any code that calls synchronous `Stream.Read` on response content; the fix is either an explicit opt-out or a manual copy to `MemoryStream`.
Removing `NavigationException` from static SSR `NavigateTo` calls eliminates a long-standing behavioral split between rendering modes, but it also silently breaks any code that caught that exception to short-circuit execution.
The shift from `blazor.boot.json` to an inlined config inside `dotnet.js` and the removal of custom Blazor caching both point toward a simpler, browser-native asset story that relies on standard fingerprinting and HTTP caching rather than framework-specific mechanisms.