Special Offer: My C#/.NET Bootcamp Course is out now. Get 10% OFF using the code FRIENDS10.

In web development, form handling and input validation can be a daunting and laborious task. Most of the time, there is no out-of-the-box solution that helps us, developers, with this challenge.

Usually, the developer community and professional library authors create many different solutions, and we need to choose what’s suitable for us.

Of course, we also have the opportunity to use third-party libraries for Blazor Form handling and input validation. Still, the good news is that Blazor supports basic form handling and input validation out-of-the-box.

In this article, we will build an UserForm component that accepts different input types, performs input validation, and handles the form submit.

Filled Form Component for User data

You can follow along using the default Blazor application template within Visual Studio. All the code shown in this article is written in a single UserForm.razor component file.

Basic Form Handling

Blazor provides an EditForm component that wraps the HTML form tag and adds convenient functionality to handle user input.

The Model property allows us to bind an instance of a model class to the form. We can create an instance of the class in the @code block of the form component and bind the instance to the EditForm component using the Model property.

<EditForm Model="User">
</EditForm>

@code {
  public UserModel User { get; set; }
  
  public class UserModel
  {
    public string Username { get; set; }
    public DateTime DateOfBirth { get; set; }
    public int LuckyNumber { get; set; }
    public UserType Type { get; set; }
  }

  public enum UserType
  {
    User,
    SuperUser,
    Admin
  }
}

Handling the Form Submit

We have two different options for how to handle the submit of the form.

We can use the OnSubmit property and provide a method that gets executed whenever the user clicks the submit button. Using this approach, we need to handle validation ourselves. This approach gives us the most freedom, but we also have to write more code.

The other approach is to use the OnValidSubmit and OnInvalidSubmit properties. Blazor performs input validation, and depending on the validation result, either the method bound to the OnValidSubmit or the OnInvalidSubmit property will be called.

<EditForm Model="User" OnValidSubmit="HandleValidSubmit">
</EditForm>

@code {
  public UserModel User { get; set; }
  // UserModel definition omitted
  public void HandleValidSubmit()
  {
    // Save User object to backend
  }
}

We want to use the default input validation and build a simple solution. That’s why we bind a HandleValidSubmit method to the OnValidSubmit property of the EditForm component.

Input Wrappers Provide Value Binding

Now that we have the EditForm component in place, we need to add input fields to the form. Blazor not only offers a wrapper component for the form but also for the different input types.

Text Input

The InputText wrapper component handles input fields of type text.

<InputText @bind-Value="User.Username" />

We can bind the Value property using the @bind-Value syntax to a property of the UserModel class referenced in the Model property of the EditForm component.

It is a two-way binding, meaning that the user input gets stored in the property, and if we initialize the property with a value, it will be displayed as the value of the form field on the screen.

Date Input

The InputDate wrapper component handles input fields of type date.

<InputNumber @bind-Value="User.LuckyNumber" />

Value binding works the same as explained for the UserInput wrapper.

InputSelect

The InputSelect wrapper component handles select fields. In contrast to the very simple wrappers discussed before, the select input also needs options.

Let’s take a look at a convenient way to define a select input based on an enum type.

<InputSelect @bind-Value="User.Type">
  @{
    foreach (var value in Enum.GetValues(typeof(UserType)))
    {
      <option value="@value">@value</option>
    }
  }
</InputSelect>

The InputSelect wrapper component also offers a bindable Value property. Further, we use a foreach loop to create the option tags based on the UserType enum type.

Additional built-in components

There are additional built-in form components available that we can use to create form fields.

We can also implement custom form components inheriting from the InputBase class.

Submit the Form Using an HTML5 Button

So far, we have used wrapper components for the form element and the input fields. For the submit button, we can use standard HTML5.

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

The Completed UserForm Component

In the constructor of the UserForm component, we create an instance of the UserModel class.

We can also assign default values to the properties of the Model class. Values set on the object and bound to a form field will be shown on the screen when the user navigates to the component.

The completed UserForm component looks like this:

<EditForm Model="User" OnValidSubmit="HandleValidSubmit">
  <InputText @bind-Value="User.Username" />
  <InputDate @bind-Value="User.DateOfBirth" />
  <InputNumber @bind-Value="User.LuckyNumber" />
  <InputSelect @bind-Value="User.Type">
  @{
    foreach (var value in Enum.GetValues(typeof(UserType)))
    {
      <option value="@value">@value</option>
    }
  }
  </InputSelect>
  <button type="submit">Submit</button>
</EditForm>

@code {
  public UserModel User { get; set; }

  public UserForm()
  {
    User = new UserModel { DateOfBirth = DateTime.Today };
  }

  public void HandleValidSubmit()
  {
    // Save User object to backend
  }

  public class UserModel
  {
    public string Username { get; set; }
    public DateTime DateOfBirth { get; set; }
    public int LuckyNumber { get; set; }
    public UserType Type { get; set; }
  }

  public enum UserType
  {
    User,
    SuperUser,
    Admin
  }
}

Input Validation Rules Using Data Annotations

Now that we implemented the UserForm component, we want to add simple input validation. It helps to make sure that the user provides the information required to fulfill our application’s needs.

Blazor supports validation based on data annotations from the System.ComponentModel.DataAnnotations namespace.

Let’s add a few validation rules using data annotations for the UserModel class.

public class UserModel
{
  [Required]
  [MaxLength(15)]
  public string Username { get; set; }

  [Required]
  public DateTime DateOfBirth { get; set; }

  [Required]
  public int LuckyNumber { get; set; }

  [Required]
  public UserType Type { get; set; }
}

Using the data annotation attributes, we mark all the properties as required and restrict the username’s max length to 15 characters.

There are more predefined validation attributes that you can use, for example, to validate email addresses, credit card numbers, or phone numbers.

You can also implement custom validation rules implementing an attribute based on the ValidationAttribute base class.

Using the Validation Rules in the UserForm Component

It’s not enough to define the validation rules on the class we bind to the Model property of the EditForm component.

We also need to specify that the EditForm component uses the data annotations as validation rules. Luckily, Blazor offers the DataAnnotationsValidator component to make things simple.

<EditForm Model="User" OnValidSubmit="HandleValidSubmit">
  <DataAnnotationsValidator />
  <!-- code omitted -->
</EditForm>

We enable input validation based on data annotations by placing the DataAnnotationsValidator as a child component of the EditForm component.

Displaying Validation Errors

As long as the user correctly fills in the form, we don’t have to worry, but what if the user makes a mistake and the form is in an invalid state?

If the form is in an invalid state, we need to make sure that we let the user know about the validation errors and how he can fix the mistakes.

Blazor offers the ValidationSummary component to display all the validation error messages on the form.

<EditForm Model="User" OnValidSubmit="HandleValidSubmit">
  <DataAnnotationsValidator />
  <ValidationSummary />
  <!-- code omitted -->
</EditForm>

Like the DataAnnotationsValidator component discussed before, we can add the ValidationSummary component as a child component of the EditForm component.

Blazor Form with validation errors

If we input invalid data into the form, we can now see the validation errors above the form fields.

Bonus: Making the Form Look Great

I purposely cut all the code example down as much as possible to demonstrate how the predefined Blazor components work.

To make it all look great, let’s add a few Bootstrap classes. Bootstrap is a user interface framework that is already included in the default Blazor application template.

The completed UserForm component:

@using System.ComponentModel.DataAnnotations;

<h3 style="margin-bottom: 20px;">User</h3>

<EditForm Model="User" OnValidSubmit="HandleValidSubmit">
  <DataAnnotationsValidator />
  <ValidationSummary />
  <div class="form-group">
    <label for="dateInput">Username</label>
    <InputText class="form-control" @bind-Value="User.Username" />
  </div>
  <div class="form-group">
    <label for="dateInput">Date of Birth</label>
    <InputDate class="form-control" @bind-Value="User.DateOfBirth" />
  </div>
  <div class="form-group">
    <label for="dateInput">Lucky Number</label>
    <InputNumber class="form-control" @bind-Value="User.LuckyNumber" />
  </div>
  <div class="form-group">
    <label for="categoryInput">Type</label>
    <InputSelect class="form-control" @bind-Value="User.Type">
      @{
        foreach (var value in Enum.GetValues(typeof(UserType)))
        {
          <option value="@value">@value</option>
        }
      }
    </InputSelect>
  </div>
  <div>
    <button type="submit" class="btn btn-primary">Submit</button>
  </div>
</EditForm>

@code {
  public UserModel User { get; set; }

  public UserForm()
  {
    User = new UserModel { DateOfBirth = DateTime.Today };
  }

  public void HandleValidSubmit()
  {
    // Save User object to backend
  }

  public class UserModel
  {
    [Required]
    [MaxLength(15)]
    public string Username { get; set; }

    [Required]
    public DateTime DateOfBirth { get; set; }

    [Required]
    public int LuckyNumber { get; set; }

    [Required]
    public UserType Type { get; set; }
  }

  public enum UserType
  {
    User,
    SuperUser,
    Admin
  }
}

Summary

Blazor offers many predefined components to handle forms. We can use the EditForm component to bind an instance of a model class to the form and to bind the method to handle the form submit.

Various wrapper components help us defining input fields and binding the value to a property of the EditForm‘s Model.

We can define input validation rules using data annotations on the model class. We can even implement custom validation rules and apply them with the same strategy. The DataAnnotationsValidator component enables data annotations as validation rules.

The ValidationSummary component displays the validation errors on the form.

Bootstrap helps us formatting the form and make it visually appealing without writing additional CSS.

 

Claudio Bernasconi

I'm an enthusiastic Software Engineer with a passion for teaching .NET development on YouTube, writing articles about my journey on my blog, and making people smile.