---
name: blazor
description: |
Builds Blazor WASM components for admin and main UI applications.
Use when: Creating/modifying Razor components, configuring render modes, implementing authentication, managing component state, or working with MudBlazor components.
allowed-tools: Read, Edit, Write, Glob, Grep, Bash, mcp__context7__resolve-library-id, mcp__context7__query-docs
---
# Blazor Skill
Sorcha uses Blazor with hybrid rendering (Server + WebAssembly). The Admin UI (`src/Apps/Sorcha.Admin/`) runs behind YARP API Gateway. Components use MudBlazor for UI and support three render modes: static server, interactive server, and interactive WASM.
## Quick Start
### Render Mode Selection
```razor
@* WASM - Complex interactive pages (Designer, Diagrams) *@
@page "/designer"
@rendermode InteractiveWebAssembly
@attribute [Authorize]
@* Server - Admin pages needing real-time SignalR *@
@page "/admin/audit"
@rendermode @(new InteractiveServerRenderMode(prerender: false))
@attribute [Authorize(Roles = "Administrator")]
@* Static - Public pages (Login) - no @rendermode directive *@
@page "/login"
@attribute [AllowAnonymous]
```
### Component with Loading State
```razor
@inject HttpClient Http
@if (_isLoading && !_hasLoadedOnce)
{
}
else if (_data != null)
{
@_data.Title
}
else if (_errorMessage != null)
{
@_errorMessage
}
@code {
private DataDto? _data;
private string? _errorMessage;
private bool _isLoading;
private bool _hasLoadedOnce;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
await LoadDataAsync();
}
private async Task LoadDataAsync()
{
_isLoading = true;
try
{
_data = await Http.GetFromJsonAsync("/api/data");
_hasLoadedOnce = true;
}
catch (Exception ex)
{
_errorMessage = ex.Message;
}
finally
{
_isLoading = false;
StateHasChanged();
}
}
}
```
## Key Concepts
| Concept | Usage | Example |
|---------|-------|---------|
| Render Mode | Control where component runs | `@rendermode InteractiveWebAssembly` |
| CascadingParameter | Receive parent state | `[CascadingParameter] MudBlazor.IDialogReference? MudDialog` |
| OnAfterRenderAsync | Initialize after DOM ready | `if (firstRender) await LoadAsync();` |
| StateHasChanged | Trigger re-render | Call after async state updates |
| NavigationManager | Programmatic navigation | `Navigation.NavigateTo("/", forceLoad: true)` |
## Project Structure
| Project | Purpose | Render Mode |
|---------|---------|-------------|
| `Sorcha.Admin` | Server host, auth, API proxy | Server + prerender |
| `Sorcha.Admin.Client` | WASM components | WebAssembly |
| `Sorcha.UI.Core` | Shared components | Both |
| `Sorcha.UI.Web` | Main UI server | Server |
| `Sorcha.UI.Web.Client` | Main UI WASM | WebAssembly |
## Common Patterns
### MudBlazor Dialog
```razor
Cancel
OK
@code {
[CascadingParameter] MudBlazor.IDialogReference? MudDialog { get; set; }
private string _value = "";
private void Cancel() => MudDialog?.Close();
private void Submit() => MudDialog?.Close(DialogResult.Ok(_value));
}
```
### Opening Dialog from Parent
```csharp
var dialog = await DialogService.ShowAsync("Login");
var result = await dialog.Result;
if (result is { Canceled: false })
{
// Handle success
}
```
## See Also
- [patterns](references/patterns.md) - Component and authentication patterns
- [workflows](references/workflows.md) - Development and deployment workflows
## Related Skills
- See the **aspire** skill for service discovery configuration
- See the **signalr** skill for real-time notifications
- See the **jwt** skill for authentication token handling
- See the **yarp** skill for API Gateway configuration
- See the **mudblazor** skill for component library details
## Documentation Resources
> Fetch latest Blazor/MudBlazor documentation with Context7.
**Library ID:** `/websites/mudblazor` _(MudBlazor component library documentation)_
**Recommended Queries:**
- "MudBlazor dialog service usage"
- "MudBlazor form validation"
- "MudBlazor data grid filtering"