Blazor EditForm Validation – Custom Rules & Examples

Learning Blazor EditForm and Validation
This post is part 5 of 12 in the series Blazor Tutorial: Build Next-Gen Web Applications

Are you sure your Blazor forms are validating the right way? Many developers rely solely on built-in validation messages and hope for the best. But here’s the thing — without a deeper understanding of how EditForm validation truly works in Blazor, you might be missing critical behavior, especially in real-world apps.

Let’s demystify the whole validation flow of EditForm in Blazor, clarify the rules behind DataAnnotationsValidator, ValidationSummary, ValidationMessage, and most importantly — show how you can take control of the process and inject your own custom validation logic.

What is EditForm in Blazor?

EditForm is a core component in Blazor used to handle user inputs and form submissions. It binds an object to a form and wires up validation using built-in or custom validation mechanisms. This means you can encapsulate model binding, submission, and validation in one compact UI component.

Here’s a basic example:

<EditForm Model="person" OnValidSubmit="HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <InputText id="name" @bind-Value="person.Name" />
    <ValidationMessage For="@(() => person.Name)" />

    <button type="submit">Submit</button>
</EditForm>

Explanation:

  • Model binds the form to an object (person in this case).
  • DataAnnotationsValidator enables validation based on attributes like [Required], [StringLength], [Range], and more.
  • ValidationSummary shows all validation errors in a summary at the top of the form.
  • ValidationMessage displays a validation message next to the specific field it relates to.

This setup enables a declarative and streamlined approach to form handling.

How Does Validation Actually Work?

Blazor uses the EditContext under the hood to manage form state and validation. Understanding this is key to implementing advanced logic.

Behind the scenes:

  1. When a user modifies a field, EditContext marks the field as “modified” and triggers field-level validation.
  2. On form submission, Blazor performs model-wide validation, evaluating all rules from DataAnnotations or any custom validators.
  3. If all validations pass, OnValidSubmit is invoked. Otherwise, the form renders the associated validation errors.

Here’s how you can tap into EditContext and add logging or custom logic:

@code {
    private EditContext editContext;
    private Person person = new();

    protected override void OnInitialized()
    {
        editContext = new EditContext(person);
        editContext.OnValidationRequested += (s, e) => Console.WriteLine("Validation Requested");
        editContext.OnFieldChanged += (s, e) => Console.WriteLine($"Field changed: {e.FieldIdentifier.FieldName}");
    }
}

This gives full visibility into user interactions and validation triggers.

How to Add Custom Validation Logic

Blazor validation supports simple rules via annotations. But complex applications often require rules that go beyond that, such as conditional checks, multi-field consistency, or external API-based validations.

Option 1: Implement IValidatableObject

Implementing IValidatableObject allows cross-field validation logic inside your model. It’s powerful for cases like ensuring password and confirm password fields match.

public class Person : IValidatableObject
{
    public string Name { get; set; }
    public string ConfirmName { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (string.IsNullOrWhiteSpace(Name))
        {
            yield return new ValidationResult("Name is required.", new[] { nameof(Name) });
        }

        if (Name != ConfirmName)
        {
            yield return new ValidationResult("Name and confirmation must match.", new[] { nameof(ConfirmName) });
        }
    }
}

This method is great when business rules live within the domain model.

Option 2: Use a Custom Validator Component

For more dynamic scenarios, you can inject validation errors programmatically. This is helpful when validation depends on external services (like username availability).

public class CustomValidator : ComponentBase
{
    [CascadingParameter] EditContext CurrentEditContext { get; set; }
    private ValidationMessageStore messageStore;

    protected override void OnInitialized()
    {
        messageStore = new ValidationMessageStore(CurrentEditContext);
        CurrentEditContext.OnValidationRequested += (s, e) => 
        {
            messageStore.Clear();
            messageStore.Add(() => person.Name, "Custom name validation error.");
        };
    }
}

You can dynamically add/remove messages based on runtime logic.

Integrating FluentValidation

For a more fluent syntax and separation of concerns, FluentValidation is a great choice. It supports complex rules, reusable validators, and localized messages.

public class PersonValidator : AbstractValidator<Person>
{
    public PersonValidator()
    {
        RuleFor(x => x.Name)
            .NotEmpty().WithMessage("Name is required.")
            .MinimumLength(3).WithMessage("Name must be at least 3 characters long.");

        RuleFor(x => x.Age)
            .InclusiveBetween(18, 60).WithMessage("Age must be between 18 and 60.");
    }
}

To integrate with Blazor, you’ll need to manually validate via dependency injection and handle error propagation through ValidationMessageStore.

FAQ: Common Questions About Blazor Validation

Can I validate on blur?

Yes! By default, Blazor validates on submit. To validate on blur, handle the FieldChanged event from the EditContext and call NotifyFieldChanged().

Can I show custom messages per field?

Yes. Use ValidationMessageStore to target individual fields and control message display precisely.

How do I reset validation?

You can reset the validation state by calling:
editContext.MarkAsUnmodified();
messageStore.Clear();
editContext.NotifyValidationStateChanged();


This clears messages and resets modified state, ideal after successful submission.

Conclusion: Make Blazor Forms Work for You

Blazor’s EditForm gives you a solid foundation for form handling and validation. But knowing how to plug into the validation lifecycle unlocks serious flexibility. From IValidatableObject to custom validators and full integration with FluentValidation, you can build robust forms that scale with your app’s complexity.

Start small — inspect EditContext, try a custom validation message — and scale up as your forms grow. Mastering this lets you build user-friendly forms that behave as expected and guide users effectively.

Want more deep dives like this? Drop a comment or check other posts in the Blazor series!

Leave a Reply

Your email address will not be published. Required fields are marked *