In this series, I’m going to show you two lightweight ways to validate forms on the front end. Both take advantage of newer web APIs. I’m also going to teach you how to push browser support for these APIs back to IE9 (which provides you with coverage for 99.6% of all web traffic worldwide).
Finally, we’ll take a look at MailChimp’s sign-up form, and provide the same experience with 28× less code.
It’s worth mentioning that front-end form validation can be bypassed. You should always validate your code on the server, too.
Alright, let’s get started!
Constraint Validation in HTML (You are here!)
A Validity State API Polyfill
Validating the MailChimp Subscribe Form
The Incredibly Easy Way: Constraint Validation
Through a combination of semantic input types (for example, ) and validation attributes (such as required and pattern), browsers can natively validate form inputs and alert users when they’re doing it wrong.
Support for the various input types and attributes varies wildly from browser to browser, but I’ll provide some tricks and workarounds to maximize browser compatibility.
Basic Text Validation
Let’s say you have a text field that is required for a user to fill out before the form can be submitted. Add the required attribute, and supporting browsers will both alert users who don’t fill it out and refuse to let them submit the form.
A required text input in Chrome.
Do you need the response to be a minimum or maximum number of characters? Use minlength and maxlength to enforce those rules. This example requires a value to be between 3 and 12 characters in length.
Error message for the wrong number of characters in Firefox.
The pattern attribute let’s you run regex validations against input values. If you, for example, required passwords to contain at least 1 uppercase character, 1 lowercase character, and 1 number, the browser can validate that for you.
Wrong format error message in Safari.
If you provide a title attribute with the pattern, the title value will be included with any error message if the pattern doesn’t match.
Wrong format message in Opera, with title text explaining RegEx.
You can even combine it with minlength and (as seems to be the case with banks, maxlength) to enforce a minimum or maximum length.
See the Pen Form Validation: Basic Text by Chris Ferdinandi (@cferdinandi) on CodePen.
The number input type only accepts numbers. Browsers will either refuse to accept letters and other characters, or alert users if they use them. Browser support for input[type=number] varies, but you can supply a pattern as a fallback.
By default, the number input type allows only whole numbers.
You can allow floats (numbers with decimals) with the step attribute. This tells the browser what numeric interval to accept. It can be any numeric value (example, 0.1 ), or any if you want to allow any number.
You should also modify your pattern to allow decimals.
If the numbers should be between a set of values, the browser can validate those with the min and max attributes. You should also modify your pattern to match. For example, if a number has to be between 3 and 42, you would do this:
See the Pen Form Validation: Numbers by Chris Ferdinandi (@cferdinandi) on CodePen.
Validating Email Addresses and URLs
The email input type will alert users if the supplied email address is invalid. Like with the number input type, you should supply a pattern for browsers that don’t support this input type.
Email validation regex patterns are a hotly debated issue. I tested a ton of them specifically looking for ones that met RFC822 specs. The one used below, by Richard Willis, was the best one I found.
One “gotcha” with the the email input type is that it allows email addresses without a TLD (the “example.com” part of “[email protected]”). This is because RFC822, the standard for email addresses, allows for localhost emails which don’t need one.
If you want to require a TLD (and you likely do), you can modify the pattern to force a domain extension like so:
Similarly, the url input type will alert users if the supplied value is not a valid URL. Once again, you should supply a pattern for browsers that don’t support this input type. The one included below was adapted from a project by Diego Perini, and is the most robust I’ve encountered.
Like the email attribute, url does not require a TLD. If you don’t want to allow for localhost URLs, you can update the pattern to check for a TLD, like this.
See the Pen Form Validation: Email & URLs by Chris Ferdinandi (@cferdinandi) on CodePen.
There are a few really awesome input types that not only validate dates but also provide native date pickers. Unfortunately, Chrome, Edge, and Mobile Safari are the only browsers that implement it. (I’ve been waiting years for Firefox to adopt this feature! Update: this feature should hopefully be coming to Firefox in the near future, too.) Other browsers just display it as a text field.
As always, we can provide a pattern to catch browsers that don’t support it.
The date input type is for standard day/month/year dates.
In supporting browsers, the selected date is displayed like this: MM/DD/YYYY (caveat: in the US. This can vary for users in other countries or who have modified their date settings). But the value is actually in this format: YYYY-MM-DD.
You should provide guidance to users of unsupported browsers about this format—something like, “Please use the YYYY-MM-DD format.” However, you don’t want people visiting with Chrome or Mobile Safari to see this since that’s not the format they’ll see, which is confusing.
See the Pen Form Validation: Dates by Chris Ferdinandi (@cferdinandi) on CodePen.
A Simple Feature Test
We can write a simple feature test to check for support, though. We’ll create an input[type=date] element, add a value that’s not a valid date, and then see if the browser sanitizes it or not. You can then hide the descriptive text for browsers that support the date input type.