One of the great new features of HTML5 is the new collection of input field types (like date, email, etc.) Modern browsers have better widgets for the input types to make it easier to pick dates and to choose the correct keyboard in mobile (for example). But they can also be combined with the form validation API to validate the data input into forms.

Validating HTML5 Input Types

Modern browsers supporting the form validation API automatically validate that the data entered into an input matches the input type. For example, if you use:

<input type="email">

the browser will validate that the text entered is an email address. If you use an input of type number, it will validate any that the content is a number and validate any min, max, or step attributes that you set. It will also require that you complete any inputs that have the required attribute.

When you submit the form, the browser displays a nice little pop-up tooltip to let you know what errors you’ve made.

See the Pen HTML5 Form Validation 1 by Shaun Kelly (@6stringbeliever) on CodePen.

CSS

In addition to the pop-up messages, HTML5 form validation also gives you three CSS pseudo classes you can use to style input elements: :valid, :invalid, and :required. These pseudo classes update as you type. Here’s an example:

See the Pen HTML5 Form Validation 2 by Shaun Kelly (@6stringbeliever) on CodePen.

Custom Validation

Sometimes the built in validations don’t work for you. Perhaps you’re not okay with “b@jo” validating as a legit email address. Perhaps you need to validate something new like some annoying password requirements (must include six uppercase letters, two numbers, one special character, your middle name, your high school crush). Good news! Custom validation has you covered!

Just call setCustomValidity() on the input element with whatever your desired error message is to set the input as invalid. Call setCustomValidity() with no error message to return the input to a valid state.

See the Pen HTML5 Form Validation 3 by Shaun Kelly (@6stringbeliever) on CodePen.

Creating a Better User Experience

The default behaviors, while a nice freebie to progressively enhance upon, leave something to be desired from a user experience perspective.

  • First of all, they don’t trigger until you attempt to submit the form.
  • Second, the browser only displays a validation message for the first invalid field when you submit the form. If more than one field is invalid, you won’t find out until you fix the first one and try to submit again.

Ideally, you want to validate input fields as soon as the user starts typing. Of course, you don’t want to have one of those annoying forms that says your input is invalid before you’ve finished entering any data, so I think the best approach is to wait to validate a field until that field loses focus, then validate the fields as the user types.

Unfortunately, there’s no way to programmatically trigger the browser to display the validation message. So, you basically have to throw those built in tooltips out and then roll your own validation. Fortunately, we can use the rest of the web validation APIs to create and display our own validation messages in the manner we choose.

Short Circuiting Validation

The first thing we need to do is to tell the browser not to automatically run validation checks on form submit. We do this using the novalidate attribute on the form:

<form novalidate>

We’re now responsible for asking the browser to validate fields and for displaying validation messages in whatever manner we choose.

Checking Validation

At any time you can check the validation state of the entire form or of a single input element using checkValidity(), which simply returns a boolean indicating if the element or form validates.

Getting and Displaying Validation Messages

If you want to display validation messages yourself, at any time, you can get the validation message using the intput element’s validationMessage property. This property contains either the browser-default message for the input’s state or the message set by setCustomValidity().

See the Pen HTML5 Form Validation 4 by Shaun Kelly (@6stringbeliever) on CodePen.

Blocking Form Submission

It’s pretty simple to block form validation until the form validates. You can call checkValidity() on the form element rather than individual elements. This will only return true if all the elements in form are valid. Call this in an event listener for the form and set the disabled attribute of the submit button based on the results:

See the Pen HTML5 Form Validation 5 by Shaun Kelly (@6stringbeliever) on CodePen.

Boo, Safari

HTML5 form validation has great support across modern browsers… except Safari. Safari supports the API, but it doesn’t prevent invalid forms from being submitted and it doesn’t display the nice little popups like Chrome and Firefox.

The other big downer with Safari is that the validation messages are not at all user friendly. For example, if you don’t complete a required field, the validation message in Chrome and Firefox is “Please fill out this field.” In Safari, it’s “value missing”. For a bad email address, Safari just says “type mismatch”. So, you can’t count on an HTMLInputElement’s validationMessage property in Safari unless you set it yourself using setCustomValidation().

Feature Detection

Feature detecting the form validation API is simple:

if (typeof HTMLInputElement.prototype.checkValidity === 'function') {
  // Yay, we can use it!
} else {
  // Aww, no validation :(
}

If you use Modernizr, use:

if (Modernizr.formValidation && Modernizr.whateverInputTypesYouNeed) {
  // Yay, we can use it!
} else {
  // Aww, no validation :(
}

Muchas Gracias

Credit for most of what I have learned about web form validation goes to Cameron Pittman and Ido Green’s Udacity course on web forms, MDN’s Data Validation API reference, and a bunch of practice working through the Senior Web Developer nanodegree at Udacity.