Scoped, nestable FluentValidation for Blazor forms. Use it to validate the form root, a nested model, or a routed region of a form without giving up Blazor's EditContext flow.
Note
Status: 1.0-alpha. The public API is intended to be stable, but changes may occur as the library matures.
Note
Repository rename: this repository used to be called Tenekon.FluentValidation.Extensions. It was renamed to Tenekon.Extensions.FluentValidation.Blazor to match the single package it ships.
Blazor's built-in validation flow is centered around a single EditContext, but real forms often split into nested components, repeating items, and scoped sub-regions.
This package lets you:
- validate the whole form with FluentValidation
- attach validators to nested models and collection items
- keep nested validators connected to the parent form lifecycle
- limit validation to selected branches of the model when needed
Install the package:
dotnet add package Tenekon.Extensions.FluentValidation.BlazorIf you want to resolve validators from dependency injection by using ValidatorType, also install:
dotnet add package FluentValidation.DependencyInjectionExtensionsIf you prefer, you can skip the DI extensions package and pass a validator instance through the Validator parameter instead.
using FluentValidation;
builder.Services.AddValidatorsFromAssemblyContaining<PersonValidator>();using FluentValidation;
public sealed class Person
{
public string? Name { get; set; }
}
public sealed class PersonValidator : AbstractValidator<Person>
{
public PersonValidator()
{
RuleFor(x => x.Name).NotEmpty();
}
}Add the package namespace to _Imports.razor or directly in the component:
@using Microsoft.AspNetCore.Components.Forms
@using Tenekon.Extensions.FluentValidation.BlazorThen wire the validator into your EditForm:
<EditForm Model="_model" OnValidSubmit="HandleValidSubmit">
<EditModelValidatorRootpath ValidatorType="typeof(PersonValidator)" />
<label for="name">Name</label>
<InputText id="name" @bind-Value="_model.Name" />
<ValidationMessage For="() => _model.Name" />
<button type="submit">Save</button>
</EditForm>
@code {
private readonly Person _model = new();
private Task HandleValidSubmit()
{
return Task.CompletedTask;
}
}If you want to bypass DI, use Validator="new PersonValidator()" instead of ValidatorType="typeof(PersonValidator)".
| Component | Use it when |
|---|---|
EditModelValidatorRootpath |
You want to validate the main model of the current form or cascaded EditContext. |
EditModelValidatorSubpath |
You want to validate a nested object or a repeated item inside the main model. |
EditModelValidatorRoutes |
You want a validator to act only on selected branches of the model. Use it inside EditModelValidatorRootpath or EditModelValidatorSubpath. |
EditModelScope |
You want to create a scoped validation region with its own EditContext behavior. |
For worked examples of all four components, see the Validator Components Cookbook.
- Target frameworks:
net8.0,net9.0,net10.0 - FluentValidation:
12.x - Blazor forms integration: the package selects the matching
Microsoft.AspNetCore.Components.Formsversion for each target framework - Internal dependency:
FastExpressionCompiler5.x
- Cookbook: start here for usage patterns and copyable scenarios.
- Architecture: read this when you want the mental model behind root, subpath, routes, and scope behavior.
- Motivation: read this when you want the design rationale and why the package is split into rootpath, subpath, routes, and scope.
git clone https://github.com/tenekon/Tenekon.Extensions.FluentValidation.Blazor.git
cd Tenekon.Extensions.FluentValidation.Blazor
dotnet testQuestions, feedback, and design discussion are welcome in the Tenekon Community Discord.
MIT License. See LICENSE for details.