Blazorise Validation component
The Validation component allows you to verify your data, helping you find and correct errors.
Validation components are used to provide simple form validation for Blazorise input components.
When validation is used together with a Field, Blazorise also updates accessibility attributes by
default. Inputs can automatically render aria-invalid from the current validation status, while <FieldHelp> and
validation messages are combined into aria-describedby so assistive technologies announce the same guidance users see on screen.
If you need custom associations, override them per component with AriaInvalid and AriaDescribedBy, or control the
automatic behavior globally through BlazoriseOptions.AccessibilityOptions.
The basic structure for validation components is:
<Validations>is the container for all validations and can contain multipleValidationcomponents.<Validation>contains the validation logic.<Feedback>displays the validation message.<ValidationSuccess>displays the success message.<ValidationWarning>displays a non-blocking warning message.<ValidationError>displays the error message.<ValidationNone>displays a message when nothing has happened.<ValidationFeedback>groups theNone,Warning,Success, andErrorfragments in one component.
<ValidationSummary>lists all error messages.
In most cases, you only need the <Validation> component together
with <ValidationSuccess> and <ValidationError>. By default, validation runs
automatically when an input value changes. Set the Validator handler to define the rules and return the
validation result.
Disabled are skipped during validation (same as native HTML forms).
If you need to prevent user edits while submitting, prefer ReadOnly (when supported) or disable only the submit button.
Examples
Method handlers
Method handlers are the easiest way to validate fields. Blazorise provides a set of predefined handlers through the ValidationRule helper class that you can assign to the Validator parameter.
In addition to the built-in handler methods, you can also create your own. For example, the following code snippet shows a custom ValidateEmail handler.
<Validation Validator="ValidationRule.IsNotEmpty"> <TextInput Placeholder="Enter name"> <Feedback> <ValidationNone>Please enter the name.</ValidationNone> <ValidationSuccess>Name is good.</ValidationSuccess> <ValidationError>Enter valid name!</ValidationError> </Feedback> </TextInput> </Validation> <Validation Validator="ValidateEmail"> <TextInput Placeholder="Enter email"> <Feedback> <ValidationNone>Please enter the email.</ValidationNone> <ValidationSuccess>Email is good.</ValidationSuccess> <ValidationError>Enter valid email!</ValidationError> </Feedback> </TextInput> </Validation>
@code{ void ValidateEmail( ValidatorEventArgs e ) { var email = Convert.ToString( e.Value ); e.Status = string.IsNullOrEmpty( email ) ? ValidationStatus.None : email.Contains( "@" ) ? ValidationStatus.Success : ValidationStatus.Error; } }
Grouped feedbackNew
Use <ValidationWarning> when a value is acceptable but should still show non-blocking guidance.
To keep all feedback fragments together, use <ValidationFeedback> with <None>,
<Warning>, <Success>, and <Error> child fragments.
The same feedback structure applies to all Edit components (check, radio, select, etc.). Some components
have special rules when defining child content and feedback.
<Validation Validator=""> <TextInput Placeholder="Enter display name"> <Feedback> <ValidationNone>Please enter a display name.</ValidationNone> <ValidationWarning>Short display names are allowed, but longer names are easier to recognize.</ValidationWarning> <ValidationSuccess>Display name looks good.</ValidationSuccess> <ValidationError>Display name is required.</ValidationError> </Feedback> </TextInput> </Validation> <Validation Validator=""> <TextInput Placeholder="Enter username"> <Feedback> <ValidationFeedback> <None>Please enter a username.</None> <Warning>Short usernames are allowed, but longer usernames are easier to identify.</Warning> <Success>Username looks good.</Success> <Error>Username is required.</Error> </ValidationFeedback> </Feedback> </TextInput> </Validation>
@code{ void ValidateDisplayName( ValidatorEventArgs e ) { ValidateNameLength( e ); } void ValidateUserName( ValidatorEventArgs e ) { ValidateNameLength( e ); } void ValidateNameLength( ValidatorEventArgs e ) { var name = Convert.ToString( e.Value ); e.Status = string.IsNullOrWhiteSpace( name ) ? ValidationStatus.Error : name.Length < 4 ? ValidationStatus.Warning : ValidationStatus.Success; } }
Data annotations
To use data annotations with Blazorise, you must combine bothValidation and Validations
components. The Validations component groups the fields used inside a Validation
component. To make this work, you must meet two requirements:
Validationscomponent must reference the validated POCO through theModelparameter.-
Input component must bind to the model field through
@bind-{Value}(e.g.@bind-Text).
@using System.ComponentModel.DataAnnotations <Validations Mode="ValidationMode.Auto" Model=""> <Validation> <Field Horizontal> <FieldLabel ColumnSize="ColumnSize.Is2">Full Name</FieldLabel> <FieldBody ColumnSize="ColumnSize.Is10"> <TextInput Placeholder="First and last name" @bind-Value="@user.Name"> <Feedback> <ValidationError /> </Feedback> </TextInput> </FieldBody> </Field> </Validation> <Validation> <Field Horizontal> <FieldLabel ColumnSize="ColumnSize.Is2">Email</FieldLabel> <FieldBody ColumnSize="ColumnSize.Is10"> <TextInput Placeholder="Enter email" @bind-Value="@user.Email"> <Feedback> <ValidationError /> </Feedback> </TextInput> </FieldBody> </Field> </Validation> <Validation> <Field Horizontal> <FieldLabel ColumnSize="ColumnSize.Is2">Password</FieldLabel> <FieldBody ColumnSize="ColumnSize.Is10"> <TextInput Role="TextRole.Password" Placeholder="Password" @bind-Value="@user.Password"> <Feedback> <ValidationError /> </Feedback> </TextInput> </FieldBody> </Field> </Validation> <Validation> <Field Horizontal> <FieldLabel ColumnSize="ColumnSize.Is2">Re Password</FieldLabel> <FieldBody ColumnSize="ColumnSize.Is10"> <TextInput Role="TextRole.Password" Placeholder="Retype password" @bind-Value="@user.ConfirmPassword"> <Feedback> <ValidationError /> </Feedback> </TextInput> </FieldBody> </Field> </Validation> </Validations>
@code{ User user = new User(); public class User { [Required] [StringLength( 10, ErrorMessage = "Name is too long." )] public string Name { get; set; } [Required] [EmailAddress( ErrorMessage = "Invalid email." )] public string Email { get; set; } [Required( ErrorMessage = "Password is required" )] [StringLength( 8, ErrorMessage = "Must be between 5 and 8 characters", MinimumLength = 5 )] [DataType( DataType.Password )] public string Password { get; set; } [Required( ErrorMessage = "Confirm Password is required" )] [StringLength( 8, ErrorMessage = "Must be between 5 and 8 characters", MinimumLength = 5 )] [DataType( DataType.Password )] [Compare( "Password" )] public string ConfirmPassword { get; set; } [Required] public string Title { get; set; } [Range( typeof( bool ), "true", "true", ErrorMessage = "You gotta tick the box!" )] public bool TermsAndConditions { get; set; } } }
Pattern validation
If you want to validate input using a regular expression instead ofValidator handlers, use the
Pattern parameter. Components that support the pattern attribute include TextInput,
NumericInput and DateInput.
<Validation UsePattern> <TextInput Pattern="[A-Za-z]{3}"> <Feedback> <ValidationError>Pattern does not match!</ValidationError> </Feedback> </TextInput> </Validation>
Async validation
If you need to run validation using an external source or a REST API, Blazorise also supports async validation. The process is similar to a regular validator. You just need to define an awaitable handler using theAsyncValidator parameter.
@using System.Threading <Validation AsyncValidator=""> <TextInput Placeholder="Enter name"> <Feedback> <ValidationError>Enter valid name!</ValidationError> </Feedback> </TextInput> </Validation>
@code{ Random random = new Random(); async Task ValidateNameAsync( ValidatorEventArgs e, CancellationToken cancellationToken ) { cancellationToken.ThrowIfCancellationRequested(); // some long running task or call to the rest API await Task.Delay( random.Next( 1500 ) ); e.Status = string.IsNullOrEmpty( Convert.ToString( e.Value ) ) ? ValidationStatus.Error : ValidationStatus.Success; } }
Manual validation
Sometimes you don't want to validate on every input change. In that case, use the<Validations> component
to group multiple validations and then run validation manually.
In this example, the
<Validations> component encloses multiple validation components and the
Mode attribute is set to Manual. Validation is executed only when you click the submit button.
<Validations @ref="validations" Mode="ValidationMode.Manual"> <Validation Validator="@ValidationRule.IsNotEmpty"> <Field> <TextInput Placeholder="Enter first name" /> </Field> </Validation> <Validation Validator="@ValidationRule.IsNotEmpty"> <Field> <TextInput Placeholder="Enter last name" /> </Field> </Validation> <Button Color="Color.Primary" Clicked="">Submit</Button> </Validations>
@code{ Validations validations; async Task Submit() { if ( await validations.ValidateAll() ) { // do something } } }
Localization
If you want to localize your validation messages, Blazorise provides an API and the required information needed for localization.
This is done through the MessageLocalizer API. Before you use it, here's a quick breakdown of how it works.
A MessageLocalizer is straightforward. It accepts two parameters and returns a string. Its signature is:
string Localize(string message, IEnumerable<string> arguments).
Where:
formatraw validation message (format string)argumentsvalues used to populate the message
Now that you know what the API consists of, let's talk about the values it provides. The most important is the
message parameter. Each message value is represented as a raw message in the form, before it is formatted.
For example, if you have a [Required] attribute set on your model field, this message will be
"The {0} field is required.", and the arguments will contain the values needed to populate
the placeholders inside of the message.
Example
For the basic example we're going to useMessageLocalizer directly on a Validation component.
@using Blazorise.Localization <Validation MessageLocalizer=""> </Validation>
@code{ [Inject] ITextLocalizer<LocalizationValidationExample> L { get; set; } string Localize( string message, IEnumerable<string> arguments ) { // You should probably do null checks here! return string.Format( L[message], arguments.ToArray() ); } }
Global Options
Setting theMessageLocalizer on each Validation is a good approach if you want
per-component control. But a more practical way is to define it globally. If you remember
from the Start Guide, we already have Validation defined in our application startup, so we just need
to modify it a little.
services.AddBlazorise( options =>
{
options.ValidationMessageLocalizer = ( message, arguments ) =>
{
var stringLocalizer = options.Services.GetService<ITextLocalizer<YourResourceName>>();
return stringLocalizer != null && arguments?.Count() > 0
? string.Format( stringLocalizer[message], arguments.ToArray() )
: message;
};
} );
Validation summary
Sometimes you don't want to show error messages under each field. In those situations you can
use the ValidationSummary component. Once placed inside of Validations it will show
all error messages as a bullet list.
Note: The ValidationSummary component name conflicts with the
built-in Microsoft.AspNetCore.Components.Forms.ValidationSummary from Blazor.
If you are using both in the same project, reference Blazorise's version explicitly as
<Blazorise.ValidationSummary>.
<Validations Mode="ValidationMode.Manual"> <ValidationSummary Label="Following error occurs..." /> @*other validation fields*@ </Validations>
Auto Validation
By default, the form is auto-validated on page load. To validate only after the user starts entering fields, setValidateOnLoad to false.
<Validations Mode="ValidationMode.Auto" ValidateOnLoad> ... </Validations>
Validation rules
Blazorise includes some predefined validation rules, e.g.:<Validation Validator="@ValidationRule.IsNotEmpty"> ... </Validation>
IValidatableObject
This example demonstrates how to implement validation in a Blazor component using theIValidatableObject interface for custom logic. The form contains several fields bound to a CompanyInfo model, which is validated automatically using data annotations and custom validation logic.
@using System.ComponentModel.DataAnnotations <Validations @ref="" Model="" Mode="ValidationMode.Auto"> <Validation> <Field> <FieldLabel>Name</FieldLabel> <FieldBody> <TextInput @bind-Value="@Company.Name"> <Feedback> <ValidationError /> </Feedback> </TextInput> </FieldBody> </Field> </Validation> <Validation> <Field> <FieldLabel>Description</FieldLabel> <FieldBody> <TextInput @bind-Value="@Company.Description"> <Feedback> <ValidationError /> </Feedback> </TextInput> </FieldBody> </Field> </Validation> <Field> <Switch TValue="bool" Value="@Company.UseAlphaCode" ValueChanged="" ValueExpression="@(() => Company.UseAlphaCode)">Use AlphaCode</Switch> </Field> <Fields> <Validation> <Field> <FieldLabel>AlphaCode</FieldLabel> <FieldBody> <TextInput @bind-Value="@Company.AlphaCode"> <Feedback> <ValidationError /> </Feedback> </TextInput> </FieldBody> </Field> </Validation> <Validation> <Field> <FieldLabel>BetaCode</FieldLabel> <FieldBody> <TextInput @bind-Value="@Company.BetaCode"> <Feedback> <ValidationError /> </Feedback> </TextInput> </FieldBody> </Field> </Validation> </Fields> </Validations>
@code { async Task OnUseAlphaCodeChanged( bool value ) { Company.UseAlphaCode = value; if ( validationsRef != null ) { // retrigger validation for dependent properties await validationsRef.RetriggerValidation( () => Company.AlphaCode, () => Company.BetaCode ); } } Validations validationsRef; CompanyInfo Company = new CompanyInfo() { UseAlphaCode = true, }; public class CompanyInfo : IValidatableObject { [Required( ErrorMessage = "Name is required" )] public string Name { get; set; } [Required( ErrorMessage = "Description is required" )] public string Description { get; set; } public bool UseAlphaCode { get; set; } public string AlphaCode { get; set; } public string BetaCode { get; set; } [Range( 0, 999.99 )] public decimal Price { get; set; } public IEnumerable<ValidationResult> Validate( ValidationContext validationContext ) { if ( UseAlphaCode ) { if ( String.IsNullOrWhiteSpace( AlphaCode ) ) { yield return new ValidationResult( "AlphaCode is required", new[] { "AlphaCode" } ); } } else { if ( String.IsNullOrWhiteSpace( BetaCode ) ) { yield return new ValidationResult( "BetaCode is required", new[] { "BetaCode" } ); } } } } }
List of the currently available validators.
| Name | Description |
|---|---|
IsEmpty |
Check if the string is null or empty. |
IsNotEmpty |
Check if the string is not null or empty. |
IsEmail |
Check if the string is an email. |
IsAlpha |
Check if the string contains only letters (a-zA-Z). |
IsAlphanumeric |
Check if the string contains only letters and numbers. |
IsAlphanumericWithUnderscore |
Check if the string contains only letters, numbers and underscore. |
IsUppercase |
Check if the string is uppercase. |
IsLowercase |
Check if the string is lowercase. |
IsChecked |
Checks if the boolean based input is checked. |
IsSelected |
Checks if the selection based input has a valid value selected. Valid values are anything except for null, string.Empty, or 0.
|
IsFileSelected |
Checks if the file is selected. |
Best Practices
Make Errors Actionable
Place feedback next to the related field and explain how to correct the value instead of merely stating that it is invalid. Validate after meaningful interaction or submission so users are not shown errors before they have had a chance to enter a value.
Validation Layers
Long forms benefit from a validation summary, but should retain field-level messages and move focus to a useful error location after submission. Repeat all security and business validation on the server because client-side validation improves feedback but does not establish trust.
API
See the API reference for the parameters, events, methods, and related types available to the components covered on this page.