I was recently working on an HTMX and ASP.NET Core demo and wanted to limit client-to-server requests to valid requests. This is a built-in feature for HTMX, as long as you utilize HTML5 validators on your forms and inputs. As many ASP.NET Core practitioners know, the default client-side validation in ASP.NET Core is not HTML5 but a mix of custom data-val
attributes and JQuery. The current approach is acceptable, but it makes adopting new frameworks, supporting native HTML capabilities, and dropping extraneous dependencies more difficult.
Could we drop the JQuery validation dependency in favor of HTML5 validation? Luckily, we can thank OSS author Andrew White for his latest NuGet package, FinBuckle.Html5Validation. This package allows us to disable the default behavior of ASP.NET Core MVC and Razor Pages for a more modern approach.
What is HTML5 Validation?
Before HTML5, developers wrote all client-side validation using JavaScript code. While JavaScript code allowed for complex scenarios, many folks realized two things: Client-side validation has many recurring patterns, and, ultimately, it’s not a bullet-proof validation approach. Server-side validation is essential.
This realization helped HTML narrow down the scope of client-side validation, which limits requests sent to the server to client-validated ones. This validation focused on a few user input characteristics:
- Required: This field must have some value.
- Type: This field conforms to the expected integer, date, phone number, etc.
- Constraints: This field has a minimum, maximum, or fits within a specified range.
- Pattern: This field conforms to a regular expression pattern
These agreed-upon validations reduced the required JavaScript code while allowing clients to create native experiences based on the input types.
Let’s take a look at an example of an HTML5-validated form. The following code can be seen on the MDN site.
As you’ll notice, the attributes required
, pattern
, min
, max
, and type
are all used to create a validation experience with no lines of JavaScript. When attempting to submit the form, you’ll notice the client displays a message. You can also highlight inputs based on their validation status.
Awesome, right?! With a bit of CSS, we can get some UI indicators. Depending on the client, any input
with an appropriate type
will have automatic access to the native type value picker, whether it’s a date, a phone number, or a number.
OK, now that we understand what HTML5 validation gets us, how do we get that in ASP.NET Core?
Disable Client-side Validation in ASP.NET Core
This section is for folks who’d prefer to keep their models and views completely separate and write the HTML mostly by hand.
To disable the default client-side validation in ASP.NET Core MVC and Razor Pages, you can use the following lines in your Program
file.
This will prevent Razor Pages and MVC from generating the data-val
attributes commonly found on inputs in the HTML output.
This approach is fine, but I think the next section is a better option for most folks as it still relies on the model metadata that ASP.NET Core provides.
FinBuckle.HTML5Validation NuGet Package
To move towards HTML5 validation, you must first install the FinBuckle.HTML5Validation
NuGet package into your ASP.NET Core application.
Important Note: this package only works with MVC and Razor Pages.
Once added to your dependencies, you must register the package with your application’s services collection.
Internally, this method provides the ASP.NET Core pipeline with an IValidationAttributeAdapterProvider
.
This adapter gets passed an attribute and a localizer, at which point you can decide what attributes should be added to the HTML input. Let’s see an implementation for the pattern
attribute.
This is a neat part of the ASP.NET Core MVC and Razor Pages pipeline. It’s extensible to the point where folks can replace validation without changing Razor views. Speaking of Razor views, let’s see how we can use this in one.
First, let’s create a Razor PageModel.
I’m using DataAnnotations here; now, what does the view look like? (I’m using HTMX, hence the hx-
attributes).
Cool! Now we need some CSS to highlight invalid fields with some styling.
You can target several states, such as :valid
, :invalid
, and :user-invalid
. The :user-invalid
state only triggers after a user has interacted with an element, whereas you can use the :invalid
state to signify a field is invalid immediately.
Let’s run our application and submit the form.
Sweet! All looks like it’s working as expected.
Conclusion
While validation libraries can offer a lot in terms of user experience, the native validation is really good. In fact, it’s good enough to handle most client-side validation and then additionally lean on server-side validation to handle the rest.
I recommend trying this approach and seeing how far you get. You’ll likely be surprised how many dependencies you can drop in favor of native controls and validation.
As always, thanks for reading and sharing my posts. Cheers.