HTML5 Zone is brought to you in partnership with:

Raymond Camden is a developer evangelist for Adobe. His work focuses on web standards, mobile development and Cold Fusion. He's a published author and presents at conferences and user groups on a variety of topics. He is the happily married proud father of three kids and is somewhat of a Star Wars nut. Raymond can be reached via his blog at www.raymondcamden.com or via email at raymondcamden@gmail.com Raymond is a DZone MVB and is not an employee of DZone and has posted 233 posts at DZone. You can read more from them at their website. View Full User Profile

HTML5 Form Validation - The Constraint Validation API

03.22.2012
| 7458 views |
  • submit to reddit

In my last blog entry, I introduced the basic concepts of form validation under HTML5. The focus was on basic tag/attribute support. In other words, what could be done without writing JavaScript code. In today's entry I want to talk about how you can use JavaScript to further enhance and work with validation, specifically the Constraint Validation API.

At a high level, this API covers the following features:

  • Form fields have a validity property. This property is a set of keys and boolean values that represent the validity, or lack of, of a particular form. A great example of this is the numeric field type. You can specify that a form field should be numeric, higher than 0, and less than 70. The validity property would actually be able to tell you if the value wasn't a number, or was too low or too high.
  • Form fields also have a generic checkValidity() function that returns true or false. So if you don't care why a field is invalid, you can simply use that. Or you can use that before digging into the validity property to determine exactly why the field isn't valid.
  • Finally, there is a setCustomValidity() method that lets you create a custom validation error. You can think of this like a throw() call as it both lets you set a message and, by default, sets the field as being in an error state. If you use an empty string, the field is considered valid.

I began my investigation by looking at the validity property. If you read the spec (no, I'm not joking, you really should), you'll see a nice list of the validity properties and their meanings. I'm quoting here from that spec:

element . validity . valueMissing
Returns true if the element has no value but is a required field; false otherwise.

element . validity . typeMismatch
Returns true if the element's value is not in the correct syntax; false otherwise.

element . validity . patternMismatch
Returns true if the element's value doesn't match the provided pattern; false otherwise.

element . validity . tooLong
Returns true if the element's value is longer than the provided maximum length; false otherwise.

element . validity . rangeUnderflow
Returns true if the element's value is lower than the provided minimum; false otherwise.

element . validity . rangeOverflow
Returns true if the element's value is higher than the provided maximum; false otherwise.

element . validity . stepMismatch
Returns true if the element's value doesn't fit the rules given by the step attribute; false otherwise.

element . validity . customError
Returns true if the element has a custom error; false otherwise.

element . validity . valid
Returns true if the element's value has no validity problems; false otherwise.

That's quite a few properties. I created a form that made use of various new input types and wrote code to iterate over those properties and write them out so I could see in real time how the values would change based on the inputs I provided.

var fields = document.querySelectorAll("input");
for(var i=0,len=fields.length; i<len; i++) {
var thisId = fields[i].id;
var s = "<div class='results'>Validity for "+thisId;
s += "<table>";
//first, call checkValidity as a whole
s += "<tr><td><b>VALID:</b></td><td>"+fields[i].checkValidity()+"</td></tr>";
for(prop in fields[i].validity) {
s += "<tr><td>"+prop+"</td><td>"+fields[i].validity[prop]+"</td></tr>";
}
s+= "</table></div>";
fields[i].insertAdjacentHTML("afterend",s);
}

 

You can see my simple for/in loop there generating nice table rows. Also note I use the checkValidity API to show, at a high level, if the field is valid or not.

Here's an example:

I mentioned the checkValidity API and how it can be used as a shortcut for determining if a field is valid. What's cool is that you can also do it for the entire form. Here is another example:

//check the form as a whole
var form = getBySel("#mainForm");
var formStatus = getBySel("#formStatus");
formStatus.innerHTML = "<p>Form validity as a whole is "+form.checkValidity()+"</p>";

 As a quick aside, getBySel was just a shortcut function I wrote:

//jQuery is a drug - a shiny, happy drug...
function getBySel(id) { return document.querySelector(id); }

 

Put together, I've got a nice demo application that lets you test this API against a variety of constraints. Since it is entirely client-side, I'll encourage you to View Source:

Now let's look at the next piece of the puzzle - custom validation. I mentioned the setCustomValidity API before. It works like so:

Given a field - if you set any non-empty string value via setCustomValidity, it is implied that the field is in error. If you set an empty string, it is implied that the field is ok.

So that makes sense, but it feels a bit awkward to me. I know I tend to rail against making things overly complex, but it feels weird that setting a string value for the message also sets the field as being invalid. I'd rather a two step process along the lines of setValid(false);setCustomValidity("....");.

Let's look at an example. This is a bit contrived, but in the form below we want to error out if the value is ray.

<!DOCTYPE html>
<html>
<head>
<script>
function getBySel(id) { return document.querySelector(id); }

function demoForm() {
var field = getBySel("#field1");
var value = field.value;
if(value == 'ray') {
field.setCustomValidity("Ray is wack!");
} else {
        field.setCustomValidity("");
    }
}

function init() {
getBySel("#testForm").addEventListener("click",demoForm,false);
}
</script>
<style>
</style>
</head>
<body onload="init()">

<form>

<p>
Just required:
<input type="text" id="field1">
</p>

<p>
<button id="testForm">Test</button>
</p>
</form>
</body>
</html>

 

As I said - it's a rather trivial example, but you can see where I use a simple event handler to check the value of a form field. It is important to remember that once you setCustomValidity and pass a non-empty string, the field is considered in error until you setCustomValidity with an empty string. Basically you've marked the field as bad until you explicitly set it to good.

Obviously one could do something a bit more complex here. You're options are pretty much anything at all. You could do an Ajax request to ensure the value was unique. You could check other values in the form. Try the demo yourself:

Published at DZone with permission of Raymond Camden, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Lisa Coffey replied on Fri, 2014/07/11 - 5:50am

The good news is that HTML form validation is supported by all the latest desktop browsers, and most mobile browsers. The bad news is that it is only partially supported in Safari, and isn't supported at all on iOS Safari, or the default Android browser. If you need to support older versions of IE prior to IE10 you won't find any of those support form validation either.

So, what can you do if you have to support browsers that don't have support for form validation yet?

One option is to not do anything and rely on your server-side validation only. This would require no extra work on your part with extra care , but would the UX for those using unsupported browsers be satisfactory?

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.