$npx -y skills add managedcode/dotnet-skills --skill blazorBuild and review Blazor applications across server, WebAssembly, web app, and hybrid scenarios with correct component design, state flow, rendering, and hosting choices. USE FOR: building interactive web UIs with C# instead of JavaScript; choosing between Server, WebAssembly, or
| 1 | # Blazor |
| 2 | |
| 3 | ## Trigger On |
| 4 | |
| 5 | - building interactive web UIs with C# instead of JavaScript |
| 6 | - choosing between Server, WebAssembly, or Auto render modes |
| 7 | - designing component hierarchies and state management |
| 8 | - handling prerendering and hydration |
| 9 | - integrating with JavaScript when necessary |
| 10 | |
| 11 | ## Documentation |
| 12 | |
| 13 | - [Blazor Overview](https://learn.microsoft.com/en-us/aspnet/core/blazor/?view=aspnetcore-10.0) |
| 14 | - [Render Modes](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-10.0) |
| 15 | - [Performance Best Practices](https://learn.microsoft.com/en-us/aspnet/core/blazor/performance?view=aspnetcore-10.0) |
| 16 | - [State Management](https://learn.microsoft.com/en-us/aspnet/core/blazor/state-management?view=aspnetcore-10.0) |
| 17 | - [JS Interop](https://learn.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-10.0) |
| 18 | |
| 19 | ### References |
| 20 | |
| 21 | - [patterns.md](references/patterns.md) - Detailed component patterns, state management strategies, and JS interop techniques |
| 22 | - [anti-patterns.md](references/anti-patterns.md) - Common Blazor mistakes and how to avoid them |
| 23 | |
| 24 | ## Render Modes (.NET 8+) |
| 25 | |
| 26 | | Mode | Where It Runs | Best For | |
| 27 | |------|---------------|----------| |
| 28 | | `Static` | Server (no interactivity) | SEO pages, marketing content | |
| 29 | | `InteractiveServer` | Server via SignalR | Real-time apps, thin clients | |
| 30 | | `InteractiveWebAssembly` | Browser via WASM | Offline-capable, client-heavy | |
| 31 | | `InteractiveAuto` | Server first, then WASM | Best of both worlds | |
| 32 | |
| 33 | ### Applying Render Modes |
| 34 | |
| 35 | ```razor |
| 36 | @* Per-component *@ |
| 37 | @rendermode InteractiveServer |
| 38 | |
| 39 | @* Or in App.razor for global *@ |
| 40 | <Routes @rendermode="InteractiveAuto" /> |
| 41 | ``` |
| 42 | |
| 43 | ### InteractiveAuto Architecture |
| 44 | |
| 45 | ``` |
| 46 | First Request: |
| 47 | Browser → Server (Interactive Server) → Fast response |
| 48 | |
| 49 | Subsequent Requests: |
| 50 | Browser → WASM (downloaded in background) → No server needed |
| 51 | ``` |
| 52 | |
| 53 | ## Workflow |
| 54 | |
| 55 | 1. **Choose render mode based on requirements:** |
| 56 | - Need SEO? Start with Static or prerendering |
| 57 | - Need real-time? Use InteractiveServer |
| 58 | - Need offline? Use InteractiveWebAssembly |
| 59 | - Want both? Use InteractiveAuto |
| 60 | |
| 61 | 2. **Design components for reusability:** |
| 62 | - Small, focused components |
| 63 | - Parameters for customization |
| 64 | - Events for communication |
| 65 | |
| 66 | 3. **Handle state correctly:** |
| 67 | - Component state lives in component |
| 68 | - Shared state via services (DI) |
| 69 | - Persist state across prerender with `[PersistentState]` |
| 70 | |
| 71 | 4. **Validate in both environments** (for Auto mode) |
| 72 | |
| 73 | ## Current Upstream Notes |
| 74 | |
| 75 | - Treat `dotnet/aspnetcore` `v10.0.10` as servicing. It restores the original .NET 10 `OwningComponentBase.Dispose` behavior and fixes a `Virtualize` null-reference path; re-run component disposal and virtualization regression tests when upgrading. |
| 76 | - The July 2026 ASP.NET Core overview still positions Blazor as the component UI path. When existing apps update servicing packages, recheck render-mode assumptions, SignalR circuit behavior, and any interactive-auto client/server service split. |
| 77 | |
| 78 | ## Component Patterns |
| 79 | |
| 80 | ### Basic Component |
| 81 | ```razor |
| 82 | @* Counter.razor *@ |
| 83 | <button @onclick="IncrementCount"> |
| 84 | Clicked @count times |
| 85 | </button> |
| 86 | |
| 87 | @code { |
| 88 | private int count = 0; |
| 89 | |
| 90 | [Parameter] |
| 91 | public int InitialCount { get; set; } = 0; |
| 92 | |
| 93 | protected override void OnInitialized() |
| 94 | { |
| 95 | count = InitialCount; |
| 96 | } |
| 97 | |
| 98 | private void IncrementCount() => count++; |
| 99 | } |
| 100 | ``` |
| 101 | |
| 102 | ### Parameter and Event Callbacks |
| 103 | ```razor |
| 104 | @* Parent.razor *@ |
| 105 | <ChildComponent Value="@value" ValueChanged="@OnValueChanged" /> |
| 106 | |
| 107 | @* ChildComponent.razor *@ |
| 108 | @code { |
| 109 | [Parameter] public string Value { get; set; } = ""; |
| 110 | [Parameter] public EventCallback<string> ValueChanged { get; set; } |
| 111 | |
| 112 | private async Task UpdateValue(string newValue) |
| 113 | { |
| 114 | await ValueChanged.InvokeAsync(newValue); |
| 115 | } |
| 116 | } |
| 117 | ``` |
| 118 | |
| 119 | ### State Persistence (.NET 8+) |
| 120 | ```razor |
| 121 | @* Prevents double-fetch during prerender + hydration *@ |
| 122 | @code { |
| 123 | [PersistentState] |
| 124 | public List<Product> Products { get; set; } = []; |
| 125 | |
| 126 | protected override async Task OnInitializedAsync() |
| 127 | { |
| 128 | // Only fetches once, persisted across prerender |
| 129 | Products ??= await Http.GetFromJsonAsync<List<Product>>("api/products"); |
| 130 | } |
| 131 | } |
| 132 | ``` |
| 133 | |
| 134 | ## Data Access Pattern for Auto Mode |
| 135 | |
| 136 | ```csharp |
| 137 | // Shared interface |
| 138 | public interface IProductService |
| 139 | { |
| 140 | Task<List |