Friday, June 29, 2012

Creating a very basic HTML5 form validation polyfill

The latest versions of Google Chrome (16+), Mozilla Firefox (8+), and Internet Explorer (10+) all support HTML5 client-side form validation. You can use several attributes with INPUT elements to perform client-side validation, including the required, pattern, min, max, step, and maxlength attributes.
For example, you use the 'required' attribute to require a user to enter a value for an INPUT element. The following HTML form demonstrates how you can make the 'Name' field required. Notice that the value of the 'title' attribute is used to display the validation error message.
<form>
     Your Name:
     <input required="required" title="Your name is required!" />
     <input type="submit" value="Submit" />
</form>

If you want to perform client-side validation in older browsers, you need a polyfill that falls back on JavaScript. Using a polyfill, browsers that support HTML5 form validation will use it, and other browsers will run the JavaScript to perform the validation.
One of my HTML5 apps runs in Internet Explorer 9 and needs client-side form validation. IE9 does not support this natively so I had a look at the Webshims Lib polyfill. It actually looked very good but has many more features than I needed (I only needed 'required' field validation). So I decided to write my own, very basic, form validation polyfill. Here it is:
var FormValidationPolyfill = (function (window) {
    var document = window.document, supportedValidationAttrs;

    function init() {
        // Determine which of the HTML5 form validation properties
        // are supported by the browser.
        var inputElem = document.createElement('input');
        supportedValidationAttrs = (function (props) {
            for (var n = 0, attrs = {}; n < props.length; n++) {
                attrs[props[n]] = (props[n] in inputElem);
            }
            return attrs;
        })('required pattern'.split(' '));
    }

    function formSubmitHandler(e) {
        var errorMessage, childNodes = this.childNodes, invalidElement,
            inputElements = this.getElementsByTagName('input');

        for (n = 0; n < inputElements.length; n++) {
            var element = inputElements[n];
            if (!invalidElement && !supportedValidationAttrs.required) {
                // The HTML5 'required' input validation attribute
                // is not supported natively by the browser.
                if (element.hasAttribute('required')) {
                    // The input element has a required attribute
                    // and must have a value.
                    if (!element.value) {
                        invalidElement = element;
                        errorMessage = 'Please fill in all the required fields.';
                    }
                }
            }
            if (!invalidElement && !supportedValidationAttrs.pattern) {
                // The HTML5 'pattern' input validation attribute
                // is not supported natively by the browser.
                var pattern = element.getAttribute('pattern');
                // If a regex pattern has been specified, check whether
                // the element's value matches it.
                if (pattern && element.value && !(new RegExp(pattern)).test(element.value)) {
                    invalidElement = element;
                    errorMessage = 'Please match the requested format.';
                }
            }
        }

        if (invalidElement) {
            // One of the input fields is not valid.
            if (invalidElement.hasAttribute('title'))
            {
                // The invalid input element has a 'title' attribute,
                // whose value will be used as the validation error
                // message (the default behavior in HTML5 form
                // validation).
                errorMessage = invalidElement.getAttribute('title');
            }
            // Do not submit the form.
            e.preventDefault();
            // Show the validation error message.
            alert(errorMessage);
        }
    }

    function addForm(id) {
        var form = document.getElementById(id);
        if (form) {
            form.addEventListener('submit', formSubmitHandler, false);
        }
    }

    init();

    return {
        addForm: addForm
    }
})(window);
Include this script in the HEAD section of your page. Then, in the page load event, initialize each form (passing its ID value) that you want to be validated as follows:
FormValidationPolyfill.addForm('my-form-id');
Simply add a 'required' attribute to each required input field, and an optional 'title' attribute for the validation error message, like in the example at the beginning of this post.

1 comment:

  1. Hi there, thanks so much for this. I am just learning about polyfills and this page was a great help. There's another good one here too that seems to go well with your article;
    html5 polyfill example

    ReplyDelete