Custom Validation Styling in Blazor Forms with Bootstrap and FieldCssClassProvider

Posted by:

|

On:

|

,

In Blazor applications, forms play a vital role in capturing and validating user inputs. By default, Blazor’s validation system, which uses DataAnnotationValidator, automatically assigns classes like .valid and .invalid to form fields depending on their validation state. However, if you’re working with frameworks like Bootstrap, you may prefer to use its predefined styles like .is-valid and .is-invalid for validation feedback. In this article, we will explore how to customize Blazor’s validation class system using a FieldCssClassProvider to seamlessly integrate Bootstrap styles into Blazor forms.

Blazor’s Default Validation System

When you create a form in Blazor using components like <EditForm> and input fields, Blazor handles validation through the DataAnnotationValidator component. Based on the field’s state—whether it’s valid or invalid—the framework applies classes like .valid and .invalid automatically. These classes are useful for custom styling but might not align with common CSS frameworks like Bootstrap.

Bootstrap uses specific class names for valid and invalid input feedback, such as .is-valid and .is-invalid. To ensure the validation feedback in Blazor forms looks consistent with Bootstrap, we can replace the default classes with the appropriate Bootstrap classes.

Customizing Validation Styles with FieldCssClassProvider

Blazor provides a FieldCssClassProvider, which allows developers to control the CSS classes applied to input fields during validation. By overriding this provider, we can modify the classes Blazor applies to form inputs based on their state.

Here’s an example of a custom BootstrapFieldCssClassProvider:

public class BootstrapFieldCssClassProvider : FieldCssClassProvider
{
public override string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier)
{
var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();
var isModified = editContext.IsModified(fieldIdentifier);
return (isModified, isValid) switch
{
(true, true) => "form-control modified is-valid",
(true, false) => "form-control modified is-invalid",
(false, true) => "form-control",
(false, false) => "form-control"
};
}
}

In this class, we have overridden GetFieldCssClass to return Bootstrap’s form-controlis-valid, and is-invalid classes depending on whether the field has been modified and whether it passes validation.

Using the Custom Provider in Razor Components

One way to use the custom FieldCssClassProvider is by applying it directly to the EditContext in your Razor page. Here’s how you can do that:

<EditForm Model="personModel" @ref="CurrentEditForm">
<!-- Form fields go here -->
</EditForm>
@code {
public EditForm CurrentEditForm { get; set; }
protected override Task OnInitializedAsync()
{
CurrentEditForm.EditContext.SetFieldCssClassProvider(new BootstrapFieldCssClassProvider());
return base.OnInitializedAsync();
}
}

This approach works, but a more elegant solution is to encapsulate the logic inside a Blazor component and take advantage of Blazor’s cascading parameters to access the EditContext.

Creating a Reusable Blazor Component for FieldCssClassProvider

To simplify and reuse the custom validation logic, we can create a reusable Blazor component that automatically applies the FieldCssClassProvider to any form it’s placed in.

Here’s the component:

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
namespace BlazorBlog.SharedComponents.Classes
{
public class CustomCssClassProvider<ProviderType> : ComponentBase
where ProviderType : FieldCssClassProvider, new()
{
[CascadingParameter]
EditContext? CurrentEditContext { get; set; }
public ProviderType Provider { get; set; } = new();
protected override void OnInitialized()
{
if (CurrentEditContext is null)
{
throw new InvalidOperationException($"{nameof(CustomCssClassProvider<ProviderType>)} requires a cascading parameter of type {nameof(EditContext)}. For example, you can use {nameof(CustomCssClassProvider<ProviderType>)} inside an EditForm.");
}
CurrentEditContext.SetFieldCssClassProvider(Provider);
}
}
}

This component allows you to specify the FieldCssClassProvider type as a generic parameter, making it reusable with different providers if needed. The component accesses the EditContext via cascading parameters, allowing it to be used inside an <EditForm> component seamlessly.

Example Usage

Here’s an example of how you can use the CustomCssClassProvider component inside an EditForm:

<EditForm Model="personModel">
<CustomCssClassProvider ProviderType="BootstrapFieldCssClassProvider"/>
<!-- Form fields go here -->
</EditForm>

In this example, the CustomCssClassProvider automatically applies the Bootstrap validation classes to all form fields without needing any manual class assignments.

Conclusion:

Using a custom FieldCssClassProvider in Blazor allows you to align Blazor’s form validation styles with frameworks like Bootstrap, ensuring a consistent user interface. By creating reusable Blazor components such as CustomCssClassProvider, you can easily manage form validation styles across multiple forms in your application without cluttering your codebase. This approach not only improves the look and feel of your forms but also simplifies the development process by leveraging Blazor’s powerful component-based architecture.

Posted by

in

,