HTML5 introduces a couple of new attributes for implementing browser-based form validation. The
pattern attribute is a regular-expression that defines the range of valid inputs for
textarea elements and most types of
required attribute specifies whether a field is required. For browsers that yet don’t implement these attributes, we can use their values as the basis of a polyfill. We can also use them to provide a more interesting enhancement – instant form validation.
What we’re going to do in this article is far less intrusive. It’s not even full client-side validation – it’s just a subtle usability enhancement, implemented in an accessible way, which (as I discovered while testing the script) is almost identical to something that Firefox now does natively!
The Basic Concept
In recent versions of Firefox, if a
required field is empty or its value doesn’t match the
pattern then the field will show a red outline, as illustrated by the following figure.
Invalid field indication in Firefox 16
This doesn’t happen straight away of course. If it did, then every required field would have that outline by default. Instead, these outlines are only shown after you’ve interacted with the field, which is basically (though not precisely) analogous to the
So that’s what we’re going to do, using
onchange as the triggering event. As an alternative, we could use the
oninput event, which fires as soon as any value is typed or pasted into the field. But this is really too instant, as it could easily be triggered on and off many types in rapid succession while typing, creating a flashing effect which would be annoying or impossibly distracting for some users. And, in any case,
oninput doesn’t fire from programatic input, which
onchange does, and we might need that to handle things like auto-complete from third-party add-ons.
Defining the HTML and CSS
So let’s have a look at our implementation, starting with the HTML it’s based on:
<form action="#" method="post">
<legend><strong>Add your comment</strong></legend>
<label for="author">Name <abbr title="Required">*</abbr></label>
<input name="author" id="author" value=""
title="Your name (no special characters, diacritics are okay)"
type="text" spellcheck="false" size="20" />
<label for="email">Email <abbr title="Required">*</abbr></label>
<input name="email" id="email" value=""
title="Your email address"
type="email" spellcheck="false" size="30" />
<input name="website" id="website" value=""
title="Your website address"
type="url" spellcheck="false" size="30" />
<label for="text">Comment <abbr title="Required">*</abbr></label>
<textarea name="text" id="text"
spellcheck="true" cols="40" rows="10"></textarea>
<button name="preview" type="submit">Preview</button>
<button name="save" type="submit">Submit Comment</button>
This example is a simple comments form, in which some fields are required, some are validated, and some are both. The fields which have
required also have
aria-required, to provide fallback-semantics for assistive techologies that don’t understand the new
The ARIA specification also defines an
aria-invalid attribute, and that’s what we’re going to use to indicate when a field is invalid (for which there is no equivalent attribute in HTML5). The
aria-invalid attribute obviously provides accessible information, but it can be also used as a CSS hook to apply the red outline:
border:1px solid #f00;
box-shadow:0 0 4px 0 #f00;
We could just use
box-shadow and not bother with the
border, and frankly that would look nicer, but then we’d have no indication in browsers that don’t support box-shadows, such as IE8.
Now that we have the static code, we can add the scripting. The first thing we’ll need is a basic
function addEvent(node, type, callback)
node.attachEvent('on' + type, function(e)
Next we’ll need a function for determining whether a given field should be validated, which simply tests that it’s neither disabled nor readonly, and that it has either a
pattern or a
!(field.getAttribute('readonly') || field.readonly)
!(field.getAttribute('disabled') || field.disabled)
(field.getAttribute('pattern') || field.getAttribute('required'))
The first two conditions may seem verbose, but they are necessary, because an element’s
readonly properties don’t necessarily reflect its attribute states. In Opera, for example, a field with the hard-coded attribute
readonly="readonly" will still return
undefined for its
readonly property (the dot property only matches states which are set through scripting).
Once we’ve got those utilities we can define the main validation function, which tests the field and then performs the actual validation, if applicable:
var invalid =
(field.getAttribute('required') && !field.value)
if(!invalid && field.getAttribute('aria-invalid'))
else if(invalid && !field.getAttribute('aria-invalid'))
So a field is invalid if it’s required but doesn’t have a value, or it has a pattern and a value but the value doesn’t match the pattern.
pattern already defines the string form of a regular-expression, all we have to do is pass that string to the
RegExp constructor, and that will create a regex object we can test against the value. But, we do have to pre-test the value to make sure it isn’t empty, so that the regular expression itself doesn’t have to account for empty strings.
Once we’ve established whether a field is invalid, we can then control it’s
aria-invalid attribute to indicate that state – adding it to an invalid field that doesn’t already have it, or removing it from a valid field that does. Simple! Finally, to put this all into action, we need to bind the validation function to an
onchange event. It should be as simple as this:
addEvent(document, 'change', function(e, target)
However for that to work, the
onchange events must bubble (using a technique that’s usually known as event delegation), but in Internet Explorer 8 and earlier,
onchange events don’t bubble. We could just choose to ignore those browsers, but I think that would be a shame, especially when the problem is so simple to workaround. It just means a bit more convoluted code – we have to get the collections of
textarea elements, iterate through them and bind the
onchange event to each field individually:
var fields = [
for(var a = fields.length, i = 0; i < a; i ++)
for(var b = fields[i].length, j = 0; j < b; j ++)
addEvent(fields[i][j], 'change', function(e, target)
Conclusion and Beyond
So there we have it – a simple and non-intrusive enhancement for instant form validation, providing accessible and visual cues to help users complete forms.
You can download the complete example here:
Once that scripting is implemented, we’re actually only a couple of skips and hops away from a complete polyfill. Such a script is beyond the scope of this article, but if you wanted to develop it further, all of the basic blocks are there – testing whether a field should be validated, validating a field against a pattern and/or required, and binding trigger events.
I have to confess, I’m not sure it’s really worth it! If you already have this enhancement (which works in all modern browsers back to IE7), and given that you have no choice but to implement server-side validation as well, and given that browsers which support
required already use them for pre-submission validation – given all that, is there really any point adding another polyfill?