The HTML5 JavaScript form validation API

The HTML5 JavaScript form validation API

There is a JavaScript API for form validation. This API will let you use your own validation algorithm (i.e. check that you have entered the same password in two different input fields), and customize error messages. Also, together with some HTML/CSS/JavaScript you will be able to make your own message bubbles.

TYPICAL USE

Example of password checking at JS Bin,  be careful to try this example in JS Bin standalone mode (click the small black arrow on the top right of the output tab).

 

Extract from source code:

  1. <html>
  2. <head>
  3.    <title>Example of using the validation API</title>
  4.    <style>
  5.      .myForm input:invalid { backgroundcolor: lightPink;}
  6.      .myForm input:valid { backgroundcolor:lightGreen; }
  7.      .myForm input:required {border: 2px solid red;}
  8.      .myForm input:optional {border: 2px solid green;}
  9.      .myForm label { display: inlineblock; width: 140px; textalign: right; }
  10.    </style>
  11. </head>
  12. <body>
  13. <form class=“myForm”>
  14.    <fieldset>
  15.      <legend>Example use of the validation API</legend>
  16.      <label for=“password1” >Password:</label>
  17.      <input type=“password” id=“password1”oninput=checkPasswords(); required>
  18.      <p>
  19.      <label for=“password2”>Repeat password:</label>
  20.      <input type=“password” id=“password2”oninput=checkPasswords(); required>
  21.      <p>
  22.      <button>Submit</button>
  23.   </fieldset>
  24. </form>
  25.  
  26.   function checkPasswords() {
  27.       var password1 = document.getElementById(‘password1’);
  28.       var password2 = document.getElementById(‘password2’);
  29.       if (password1.value != password2.value) {
  30.           password2.setCustomValidity(‘Passwords do not match!’);
  31.       } else {
  32.          password2.setCustomValidity();
  33.       }
  34.    }
  35. </body>
  36. </html>

Explanations: the validity API proposes a setCustomValidity() method available on input DOM objects. This method allows you to customize error messages. It takes a string parameter. When this string is empty, the element is considered valid, when the string is not empty, the field is invalid and the validation error message displayed in the bubble will be equal to that string.

At lines 17 and 20 we added an input event listener: each time a key is typed, the checkPasswords() function is called.

Lines 28 and 29 get the input fields’ values, and lines 31-35 check if the passwords are the same and set the validity of the field using the validation API’s methodsetCustomValidity(error_message).

 

The validity property of input fields

The validity property of input fields helps to get error details when the field is invalid. This property tests the different types of validation error.

Here is how to get the validity property of an input field:

  1. var input = document.getElementById(‘IdOfField’);
  2. var validityState_object = input.validity;

The possible values for the validity property are:

    • valueMissing
    • typeMismatch
    • patternMismatch
    • tooLong
    • rangeUnderflow
    • rangeOverflow
    • stepMismatch
    • valid
    • customError

Here is an example at JS Bin that shows how to test the different types of validation errors, or you may try it here in your browser (enter bad values, too big, too small, enter invalid characters, etc.):

Note that testing it in Chrome/Opera/Firefox does not produce the same results. So far Opera has the most advanced implementations, however, entering “21” for example in the <input type=”number” max=”20″/> input field may yield some unexpected results depending on the browser. Test it yourself.

Source code:

  1. <!DOCTYPE html>
  2. <html>
  3. <body>
  4. function validate() {
  5.      var input = document.getElementById(‘b’);
  6.      var validityState_object = input.validity;
  7.  
  8.      if(validityState_object.valueMissing) {
  9.          input.setCustomValidity(‘Please set an age (required)’);
  10.      } else if (validityState_object.rangeUnderflow) {
  11.          input.setCustomValidity(‘Your value is too low’);
  12.      } else if (validityState_object.rangeOverflow) {
  13.          input.setCustomValidity(‘Your value is too high’);
  14.      } else if (validityState_object.typeMismatch) {
  15.          input.setCustomValidity(‘Type mismatch’);
  16.      } else if (validityState_object.tooLong) {
  17.          input.setCustomValidity(‘Too long’);
  18.      } else if (validityState_object.stepMismatch) {
  19.          input.setCustomValidity(‘stepMismatch’);
  20.      } else if (validityState_object.patternMismatch) {
  21.          input.setCustomValidity(‘patternMismatch’);
  22.      } else {
  23.          input.setCustomValidity();
  24.      }
  25. }
  26. <form class=“myForm”>
  27. <label for=“b”>Enter a value between 10 and 20: </label>
  28.  
  29. <input type=“number” name=“text” id=“b” min=“10” max=“20”
  30.         required oninput=validate();/>
  31. <button>Submit</button>
  32. </form>
  33. </body>
  34. </html>

THE VALIDATIONMESSAGE PROPERTY

It is also possible to get the validation error message, using the validationMessage property of input fields.

  1. var input = document.getElementById(‘b’);
  2.  
  3. console.log(“Validation message = “ + input.validationMessage);

 

Custom validation: changing the default behavior, aggregating error messages, removing bubbles, etc.

CRITICISM OF THE DEFAULT BEHAVIOR OF HTML5 BUILT-IN VALIDATION

The techniques we have seen so far for enhancing HTML forms are powerful and provide interesting features, but are also criticized by Web developers:

    • Browser support is still not 100% complete (Safari and Internet Explorer still lack several important features),
    • It is not possible to aggregate error messages.  On submission, browsers show an error bubble next to the first invalid field, and there is no built-in way to display all error messages for all invalid fields at the same time,
    • You cannot style the bubbles.

However, the validation API gives enough power to make your own validation behavior, overriding the default when necessary.

Here is an adaptation of work presented at the developer.telerik.com Web site.  This link is really worth reading, as it presents different approaches and gives external references for those who would like to go further.

EXAMPLE THAT SHOWS AGGREGATION OF ERROR MESSAGES + OVERRIDING DEFAULT BEHAVIOR

Try the online example at JS Bin, or try it here in your browser: enter invalid values and submit with one or two invalid fields.

 

Complete source code:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.    <meta charset=“utf-8”>
  5.    <title>Aggregating error messages</title>
  6.    <style>
  7.        input:invalid { backgroundcolor: lightPink;}
  8.        input:valid { backgroundcolor:lightGreen; }
  9.        input:required {border: 2px solid red;}
  10.        input:optional {border: 2px solid green;}
  11.  
  12.        .errormessages {
  13.            display: none;
  14.            margin: 0 10px 15px 10px;
  15.            padding: 8px 35px 8px 30px;
  16.            color: #B94A48;
  17.            backgroundcolor: #F2DEDE;
  18.            border: 2px solid #EED3D7;
  19.            borderradius: 4px;
  20.        }
  21.        fieldset {
  22.           border:1px solid;
  23.           padding:20px;
  24.        }
  25.     </style>
  26. </head>
  27. <body>
  28. <form>
  29.      <fieldset>
  30.          <legend>Submit with one or two invalid fields</legend>
  31.          <ul class=“error-messages”></ul>
  32.          <label for=“name”>Name:</label>
  33.          <input id=“name” name=“name” required>
  34.          <p>
  35.          <label for=“email”>Email:</label>
  36.          <input id=“email” name=“email” type=“email” required>
  37.          <p>
  38.          <button>Submit</button>
  39.      </fieldset>
  40. </form>
  41.  
  42.     function replaceValidationUI(form) {
  43.        // Suppress the default bubbles
  44.           form.addEventListener(“invalid”, function (event) {
  45.           event.preventDefault();
  46.        }, true);
  47.  
  48.        // Support Safari, iOS Safari, and the Android browser — each of which
  49.        // do not prevent form submissions by default
  50.        form.addEventListener(“submit”, function (event) {
  51.           if (!this.checkValidity()) {
  52.              event.preventDefault();
  53.           }
  54.        });
  55.  
  56.        // Container that holds error messages. By default it has a CSS
  57.        // display:none property
  58.        var errorMessages = form.querySelector(“.error-messages”);
  59.  
  60.        var submitButton = form.querySelector(“button:not([type=button]),
  61.                                               input[type=submit]”);
  62.  
  63.        submitButton.addEventListener(“click”, function (event) {
  64.            var invalidFields = form.querySelectorAll(“input:invalid”);
  65.            var listHtml = “”;
  66.            var errorMessagesContainer = form.querySelector(“.error-messages”);
  67.            var label;
  68.  
  69.            // Get the labels’ values of their name attributes + the validation error
  70.            // message of the corresponding input field using the validationMessage
  71.            // property of input fields
  72.            // We build a list of
  73. that we add to the error message container

  74.            for (var i = 0; i invalidFields.length; i++) {
  75.                label = form.querySelector(“label[for=” + invalidFields[ i ].id + “]”);
  76.                listHtml +=
  77. +
  78.                            label.innerHTML +
  79.                            ” “ +
  80.                            invalidFields[ i ].validationMessage +
  81.                            
  82. ;

  83.            }
  84.  
  85.            // Update the list with the new error messages
  86.            errorMessagesContainer.innerHTML = listHtml;
  87.  
  88.            // If there are errors, give focus to the first invalid field and show
  89.            // the error messages container by setting its CSS property display=block
  90.            if (invalidFields.length > 0) {
  91.               invalidFields[ 0 ].focus();
  92.               errorMessagesContainer.style.display = “block”;
  93.            }
  94.        });
  95.    }
  96.  
  97.    // Replace the validation UI for all forms
  98.    var forms = document.querySelectorAll(“form”);
  99.    for (var i = 0; i forms.length; i++) {
  100.        replaceValidationUI(forms[ i ]);
  101.    }
  102. </body>
  103. </html>

Explanations:

    • Line 32: we added an empty unnumbered list (<ul>..</ul>) to the form, with the CSS class=”error-messages”. We will use this class attribute for styling, and hiding by default, the error messages using CSS (see lines 12-20, line 13 hides the messages by default).
    • Lines 97-102 look at all forms in the document and call a function that will replace the default validation behavior for all of them: the replaceValidationUI(form) function.
    • This function first disables all default behavior (no more display of bubbles during form submission), this is done at lines 45-57.
    • Line 66: we add a click listener to the submit button of the current form.
    • Line 67 gets all invalid input fields for that form,
    • Lines 76-83: For each invalid field, we get the value of the name attribute of the corresponding label, we also get the validation error message, and we build a list item(<li>…</li>).
    • Line 86: Then we add this list element (a formatted error message corresponding to an invalid input field) to the error message container.
    • Lines 90-93: The focus is given to the first invalid field that shows an error message.
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s