Help us improve
Share bugs, ideas, or general feedback.
From dotnet-blazor
Explains Blazor component model: render modes (SSR, Interactive Server/WebAssembly/Auto), lifecycle methods, parameters, EventCallbacks, and communication via cascading values. For .NET web app developers.
npx claudepluginhub markus41/claude --plugin dotnet-blazorHow this skill is triggered — by the user, by Claude, or both
Slash command
/dotnet-blazor:blazor-componentsThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
The unified Blazor Web App model supports four render modes:
Building Blazor apps. Hosting models, render modes, routing, streaming rendering, prerender.
Creates Blazor forms with EditForm, input components, DataAnnotationsValidator, FluentValidation, and SSR handling for validation.
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Share bugs, ideas, or general feedback.
The unified Blazor Web App model supports four render modes:
@rendermode directive@page "/about"
@attribute [StreamRendering] @* Enable streaming for async data *@
<h1>About Us</h1>
<p>@_content</p>
@code {
private string? _content;
protected override async Task OnInitializedAsync()
{
_content = await ContentService.GetAboutAsync();
}
}
@rendermode InteractiveServer@rendermode InteractiveWebAssembly@rendermode InteractiveAutoConstructor → SetParametersAsync → OnInitialized[Async] → OnParametersSet[Async]
→ BuildRenderTree → OnAfterRender[Async](firstRender: true)
Parameter change → SetParametersAsync → OnParametersSet[Async]
→ BuildRenderTree → OnAfterRender[Async](firstRender: false)
Disposal → Dispose/DisposeAsync
OnInitializedAsync runs once - use for initial data loadingOnParametersSetAsync runs on every parameter change - use for dependent dataOnAfterRenderAsync runs after DOM update - use for JS interopfirstRender in OnAfterRenderAsync to avoid duplicate JS calls@* Parent *@
<ChildComponent Title="Hello" Items="@_items" OnDelete="HandleDelete" />
@* Child *@
@code {
[Parameter] public string Title { get; set; } = "";
[Parameter] public List<Item> Items { get; set; } = [];
[Parameter] public EventCallback<int> OnDelete { get; set; }
}
@* Child *@
<button @onclick="() => OnDelete.InvokeAsync(item.Id)">Delete</button>
@* Layout or parent *@
<CascadingValue Value="@_theme" Name="AppTheme">
@Body
</CascadingValue>
@* Any descendant *@
@code {
[CascadingParameter(Name = "AppTheme")] public Theme? Theme { get; set; }
}
public sealed class AppState
{
public event Action? OnChange;
private int _count;
public int Count => _count;
public void Increment()
{
_count++;
OnChange?.Invoke();
}
}
// Register as Scoped (Server) or Singleton (WASM)
<EditForm Model="@_model" OnValidSubmit="HandleSubmit" FormName="my-form">
<DataAnnotationsValidator />
<InputText @bind-Value="_model.Name" />
<ValidationMessage For="@(() => _model.Name)" />
<InputNumber @bind-Value="_model.Quantity" />
<InputDate @bind-Value="_model.DueDate" />
<InputSelect @bind-Value="_model.Category">
@foreach (var cat in _categories)
{
<option value="@cat">@cat</option>
}
</InputSelect>
<button type="submit">Save</button>
</EditForm>
@page "/doctor-who-episodes/{season:int}"
@rendermode InteractiveWebAssembly
@using System.Globalization
@using BlazorSample.Components.Layout
@attribute [Authorize]
@implements IAsyncDisposable
@inject IJSRuntime JS
@inject ILogger<DoctorWhoEpisodes> Logger
<PageTitle>Doctor Who Episode List</PageTitle>
@* Disable prerender for specific component *@
@rendermode @(new InteractiveServerRenderMode(prerender: false))
@* Disable for entire app in App.razor *@
<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />
@* Handle client-only services during prerender *@
@code {
protected override void OnInitialized()
{
// Check if service exists (null during server prerender)
if (Services.GetService<IWebAssemblyHostEnvironment>() is { } env)
environmentName = env.Environment;
}
}
// State container service
public class StateContainer
{
private string? savedString;
public string Property
{
get => savedString ?? string.Empty;
set { savedString = value; NotifyStateChanged(); }
}
public event Action? OnChange;
private void NotifyStateChanged() => OnChange?.Invoke();
}
// Register: AddScoped (Server), AddSingleton (WASM)
@implements IDisposable
@inject StateContainer StateContainer
<p>@StateContainer.Property</p>
@code {
protected override void OnInitialized() =>
StateContainer.OnChange += StateHasChanged;
public void Dispose() =>
StateContainer.OnChange -= StateHasChanged;
}
ProductDetail.razor (not productDetail.razor)Components/Pages/ProductDetail.razor@page "/product-detail"@namespace directive > RootNamespace in csproj > project namespace + folder path@* CounterPartialClass.razor *@
@page "/counter-partial-class"
<button @onclick="IncrementCount">Click me</button>
<p>Count: @currentCount</p>
// CounterPartialClass.razor.cs
namespace BlazorSample.Components.Pages;
public partial class CounterPartialClass
{
private int currentCount = 0;
private void IncrementCount() => currentCount++;
}
@key on repeated elements for efficient diffing<Virtualize> for large lists (renders only visible items)[SupplyParameterFromQuery] for query string binding[SupplyParameterFromForm] for form model binding in SSRNavigationManager.NavigateTo() for programmatic navigationIDisposable to unsubscribe from eventsErrorBoundary to catch component-level errors gracefully