Back to skills
SKILL.md
Blazor
ASecurityBlazor component patterns for interactive web UIs.
- 8 stars
- 0 votes
- 0 copies
- 16 views
- Added September 8, 2026
Works with
Security analysis
100/100Pro scans all 2 files and shows the line behind each finding
npx -y skills add ngxtm/devkit --skill blazor --agent claude-codeAre you the author of Blazor?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/ngxtm-blazor)---
name: Blazor
description: Blazor component patterns for interactive web UIs.
metadata:
labels: [blazor, components, wasm, server]
triggers:
files: ['**/*.razor', '**/*.razor.cs']
keywords: [Component, Parameter, CascadingParameter, EventCallback, StateHasChanged]
---
# Blazor
## **Priority: P1 (OPERATIONAL)**
Blazor component patterns for interactive web UIs.
## Implementation Guidelines
- **Components**: Keep components focused. Split large components into smaller ones.
- **Parameters**: Use `[Parameter]` for one-way, `EventCallback` for two-way binding.
- **Cascading Values**: Use for app-wide state (theme, user context).
- **State Management**: Component state for local, Fluxor/custom service for global.
- **Forms**: `EditForm` with `DataAnnotationsValidator` or FluentValidation.
- **JS Interop**: Use `IJSRuntime` sparingly. Prefer Blazor bindings.
- **Render Modes**: Choose based on requirements (Server, WASM, Auto in .NET 8+).
- **Streaming**: Use `[StreamRendering]` for long-loading components.
## Anti-Patterns
- **No direct DOM manipulation**: Use Blazor bindings and refs.
- **No `StateHasChanged()` in lifecycle**: Called automatically after lifecycle methods.
- **No heavy computation in render**: Move to `OnInitialized` or background task.
- **No sync JS interop in Server mode**: Causes UI blocking.
## Code
```razor
@* UserList.razor *@
@page "/users"
@attribute [StreamRendering]
@inject IUserService UserService
<PageTitle>Users</PageTitle>
<h3>Users</h3>
@if (_users is null)
{
<p><em>Loading...</em></p>
}
else if (_users.Count == 0)
{
<p>No users found.</p>
}
else
{
<div class="user-grid">
@foreach (var user in _users)
{
<UserCard User="user" OnDelete="HandleDelete" />
}
</div>
}
@code {
private List<User>? _users;
protected override async Task OnInitializedAsync()
{
_users = await UserService.GetAllAsync();
}
private async Task HandleDelete(int userId)
{
await UserService.DeleteAsync(userId);
_users = await UserService.GetAllAsync();
}
}
```
```razor
@* UserCard.razor - Reusable component *@
<div class="card">
<h5>@User.Name</h5>
<p>@User.Email</p>
<button @onclick="() => OnDelete.InvokeAsync(User.Id)">Delete</button>
</div>
@code {
[Parameter, EditorRequired]
public User User { get; set; } = default!;
[Parameter]
public EventCallback<int> OnDelete { get; set; }
}
```
```razor
@* EditForm with validation *@
<EditForm Model="@_model" OnValidSubmit="HandleSubmit" FormName="CreateUser">
<DataAnnotationsValidator />
<ValidationSummary class="text-danger" />
<div class="mb-3">
<label class="form-label">Name</label>
<InputText @bind-Value="_model.Name" class="form-control" />
<ValidationMessage For="@(() => _model.Name)" />
</div>
<div class="mb-3">
<label class="form-label">Email</label>
<InputText @bind-Value="_model.Email" class="form-control" type="email" />
<ValidationMessage For="@(() => _model.Email)" />
</div>
<button type="submit" class="btn btn-primary" disabled="@_isSubmitting">
@if (_isSubmitting)
{
<span class="spinner-border spinner-border-sm"></span>
}
Submit
</button>
</EditForm>
@code {
private CreateUserModel _model = new();
private bool _isSubmitting;
private async Task HandleSubmit()
{
_isSubmitting = true;
await UserService.CreateAsync(_model);
_isSubmitting = false;
NavigationManager.NavigateTo("/users");
}
}
```
## Reference & Examples
For lifecycle, state management, and JS interop:
See [references/REFERENCE.md](references/REFERENCE.md).
## Related Topics
aspnet-core | razor-pages | security
Files in this skill
- SKILL.md
- references/REFERENCE.md
Attribution
Comments
Loading comments…