Developers in all reaches of the web are adopting HTML5 and related technologies like CSS3 and WebGL to create more rich, dynamic, and interactive web experiences.
While powerful multimedia features like HTML5 canvas, video, and audio get a lot of attention, there are many other features in HTML5 that, while not exactly jaw-dropping, can nevertheless improve the user experience of even the most down-to-earth websites you use every day.
One such feature that I had occasion to use recently was HTML5 browser-side form validation. This allows you to imbue web forms — like the ones you see when signing up to a new site or entering your payment information in an online store — with metadata about what type of input the user is expected to provide. The browser can use this metadata to offer instant feedback to the user, making your site feel more responsive.
owser-side form validation does more than just make your site more appealing. When implemented well, it can measurably improve the speed and accuracy with which users fill out your form, which can translate into an increase in the number of successful sign-ups, purchases, and other user interactions with your site.
Web developers have used JavaScript for many years to perform browser-side form validation, but HTML5 makes it vastly easier and provides a more consistent interface and user experience. As more browsers support HTML5, expect to see more sites adopting HTML5 form validation, either to replace traditional JavaScript form validation or to complement it.
In this post, I’ll be giving a practical introduction to HTML5‘s form validation features. By adding just a few extra attributes to your HTML source, you can greatly improve the usability of your forms and start turning more would-be users and customers into actual users and customers.
Caveats
Before we get to the fun stuff, let me explain one very important thing: browser-side form validation is an excellent complement to server side validation, but always be sure to check the data on the server, too!
For one thing, not all browsers support HTML5 yet. There are some JavaScript libraries like H5F that can emulate HTML5 forms in many browsers that lack true HTML5 support, but keep in mind that JavaScript might be unavailable or disabled by the user.
Even among browsers do support HTML5 form validation, the manner in which they handle validation varies. For example, Chrome, Firefox, and Opera will each display a tooltip when a form field is invalid, explaining what the problem is. But Safari (including mobile Safari for iOS devices like the iPhone and iPad) merely displays a red outline around the field if it is invalid, or a blue outline if it is valid.
Finally, remember that a tech-savvy user (or attacker!) can bypass your browser-side form validation entirely by sending an HTTP request to your server with whatever data they want. Relying on browser-side form validation for security would be extremely unwise.
So remember: browser-side validation can help improve the user experience, but don’t rely on it. Always make sure it is possible to use forms even without it, and always perform appropriate server-side validation of any data submitted by a user.
With those warnings out of the way, let’s dive in!
The required
Attribute
One very simple way to add some validation magic to your form is the “required
“ attribute. Add this to any <input>
tag to indicate that the user is required to enter or select a value for that field. Here’s some example code for a text input form with the required
attribute:
If you are writing XHTML, or you just prefer XML syntax, you could get the same results by writing this instead:
Many modern browsers will display a message to the user if they leave a required field blank (see the image at the beginning of this article for an example). Browsers that don’t support HTML5 forms will simply ignore the required
attribute, so this is safe to use even if many of your users are still using older browsers.
Many <input>
types interpret the required
attribute as you would expect: the user must input or select some non-empty value. Besides <input>
, there are two other tags that support the required
attribute: <textarea>
(to indicate, of course, that the user must enter some text), and <select>
(to indicate that the user must select an <option>
whose value
is not empty).
One very useful, albeit slightly more complex, input type is the radio button. In this context, the required
attribute indicates that the user must select one of the radio buttons in the group. All radio buttons with the same name
attribute are considered to be part of the same group. For example [Edit: Updated to use <label>
elements]:
You only need to add the required
attribute to one of the radio buttons to affect the whole group, but I would encourage you to add it to all of them, to make your intent clear when you (or a colleague) are maintaining the site in the future.
New Input Types
HTML5 also offers some new <input>
types with their own built-in validation. Some of these input types also have special UI widgets in browsers that implement them. Other browsers will just show them as text input fields, so your users will still be able to complete the form.
One particularly useful type is email
, which indicates that the field expects some text that looks like an email address. This is particularly useful because it is notoriously tricky to validate email addresses with regular expressions (or to do it “right,” anyway). Using this input type also gives a hint to mobile devices like the iPhone/iPad that they should configure the on-screen keyboard to make it easy for the user to enter an email address.
Here’s a simple example of a field that requires the user to enter an email address:
Be aware that the email
input type will accept some unusual addresses that you might consider invalid, such as 7@9
and !#$%&'*+-/=?^_`{}|[email protected]
. It’s unlikely that a legitimate user will enter such an email address, so I usually let these cases pass through to the server, where I can apply more advanced validation rules or send an email with a confirmation link.
There are many other input types that were added in HTML5. You can use them just like in the email example above, but replace type=email
with, for example, type=url
. Here are a few of the most useful new input types that provide built-in validation:
- The
url
type checks that the value is a valid absolute URL (e.g. “http://spin.atomic.com/” or “git://github.com/atomicobject/piece_pipe.git”). However, the browser doesn’t actually check the URL to see if it points to something, only that it looks like a URL. - The
number
type checks that the value is a floating point number (e.g. “42″ or “-3.14159″). You can specify themin
andmax
attributes to limit the range of numbers allowed by the form. - The
range
type is similar to thenumber
type, but browsers that support it usually show a slider UI widget. As with thenumber
type, you can specifymin
andmax
attributes to limit the allowed range. - The
color
type checks that the value is a valid color in hex notation (e.g. “#ef3e42″), and the browser might show a color chooser UI widget. Be aware that color keywords like “red” and “darkblue” are not considered valid. - The
date
andtime
types check that the value is a valid date/time. You can specify themin
andmax
attributes (in ISO 8601 format) to limit the allowed date/time range. Some browsers might show special UI widgets for these fields, such as a calendar. The browser converts the input value to ISO 8601 when the form is submitted, although it might display and accept input from the user in another format, depending on their locale.
Unfortunately, the usefulness of the date
and time
input types is greatly diminished by the fact that not all browsers support HTML5 forms, and most users would not spontaneously choose to enter dates and times in ISO 8601 format. Until HTML5 support is more ubiquitous, I would recommend simply having separate fields for year, month, etc. There are other approaches to solving this problem, but this is a simple and reliable solution that, when done well, provides a good level of guidance to the user.
The pattern
Attribute
Sometimes, you need to validate that the user has input something in a particular custom pattern. One example of this would be a postal code, which must be a string of N numerical digits (where N depends on the country). In the US, postal codes (ZIP codes) must be at least 5 digits, but you can optionally add a hyphen and 4 extra digits to aid mail sorting and delivery.
This sort of requirement is easily expressed using the pattern
attribute, which indicates that the value must match the provided regular expression. (Regular expressions can be cryptic, but once you understand them, they are incredibly useful.) Here’s an example of how you could configure an input field to check that the text looks like a US ZIP code:
This pattern accepts 5 digits, then optionally a hyphen or space (to be forgiving toward the user) and 4 more digits. The pattern is also tolerant of leading or trailing whitespace, to avoid frustrating the user if they accidentally hit space while typing; such an error can be difficult for the user to notice. The server should be programmed to remove the spaces before processing the value, of course.
The pattern
attribute uses the same syntax as JavaScript regular expressions, but the pattern is always tested against the entire value. (In effect, the pattern has implicit ^
and $
anchors surrounding the expression.)
Also notice that I also added a title
attribute in the example above. Some browsers will use the contents of the title
attribute when displaying a tooltip to the user about why the field is invalid. This can help the user fill out the form correctly, making the experience less frustrating.
Advanced Topics and Further Reading
I have barely scratched the surface of what you can do with HTML5 forms. There are numerous other input types and attributes to configure form fields, CSS rules to style valid and invalid fields however you like, and an easy-to-use “constraint validation” JavaScript API to implement validation rules that are as complex and nuanced as you like.
If you’re interested in diving deeper into these topics, I can recommend these excellent articles and resources:
- Making Forms Fabulous with HTML5 (HTML5 Rocks)
- Forward Thinking Form Validation (A List Apart)
- Constraint Validation (Mozilla Developer Network)
- Official Specification for HTML5 Forms (W3C)
So if you’re looking for an easy way to make your site feel more responsive, give HTML5 form validation a try. To make sure you don’t leave some users out in the cold, you can use a shim library like H5F to use JavaScript to emulate HTML5 forms on older browsers.
HTML5 form validation is quick, easy, and it could even improve your love life! …Or at least your site’s metrics.
I liked your article but the nit-picky part of me cringes when I see the code samples.
To provide a clean and consistent markup style every attribute should be properly quoted (e.g. type=”text”), input tags should be self closing (e.g. have a “/” at the end of the tag) and in the case of a self-closing tag type like
input
there should not be a separate closing tag. If you’d like to wrap the input and some text in alabel
tag to afford the usability improvement that’s fine. ;-)Note: I realize that in HTML5 (unlike XHTML) according to the specs both quoted and unquoted attributes however like most I find omitting them randomly to be sloppy practice and error prone with generated code. e.g. …input type=”text” title=$titleTip value=$val name=”foo”… if the variables for $titleTip or $val evaluate to simple strings with no spaces everything works fine however if they contain spaces or quotes (e.g. O’Reily) the browser’s parsing of the page goes down in flames. For the benefit of new programmers I think it is better to show a clean, complete style. ;-)
You make a very good point. I usually write in an XHTML style like you describe, which is why I included the XHTML-style example, to show that other code styles will work too. It was a tough decision, but for this article I tried to follow the style of the examples in the W3C specification. They are not entirely consistent, but the general “style rules” I noticed were:
1. Single-word attribute values that are “standard” are usually unquoted. Hence
type=text
is unquoted (becausetext
is a standard value defined in the specification), butname="username"
is quoted (because"username"
is a value invented by me).2.
input
tags are usually not self-closing. Of course, when they wrap some other text (like in the radio example), there is a closing tag afterward.So, there is some method to the madness. Or at least, the madness is not entirely my own. :)
You are absolutely correct that if the value might be generated from a template, the value should be quoted, for safety.
What say you, dear readers? Should I update the code samples to use XHTML style, or leave them as they are?
For the comment about input tags usually not being self-closing… I disagree. From the original HTML specs (in this case a version 4 reference)… http://www.w3.org/TR/html401/interact/forms.html#h-17.4 The specs state: “Start tag: required, End tag: forbidden” thus I consider adding a closing tag to be a coding error and ensure that I never add one.
As for the quotes… as noted they are technically optional… however for the reasons I stated… and to see perfect syntax highlighting (and error detection) in my editor, I ensure all my code is properly quoted. ;-)
Found the HTML5 spec reference:
http://www.w3.org/TR/html5/syntax.html#syntax-tags
Quote: “Void elements only have a start tag; end tags must not be specified for void elements.”
which links to the Void element declaration: http://www.w3.org/TR/html5/syntax.html#void-elements
Quote: “Void elements
area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, track, wbr”
Since input is one of the void elements, it should not have a separate closing tag…
Thank you for the correction. I was mistaken about using the input tag to wrap the radio button’s label. As you pointed out, the proper way to do this is to either wrap the radio button in a label element, or use a separate label element with a “for” attribute whose value is the id of the radio button element.
I have update the radio button example to take this into account. Thanks again!