Making Forms Fabulous with HTML5

HTML5 Rocks

Introduction

Filling out forms on the web has never been exactly fun, and it can be downright painful on a mobile device with its on-screen keyboard. But modern browsers help to make this much easier by providing new semantic input types and validation.

When used properly, these features make it significantly easier for users to provide the information needed, increasing completion rates, and improving accuracy.

One study found that simply providing inline validation increased the successful completion rate by 22% and decreased time to completion by 42%.

Browser support

Currently support for the new form and input elements is widespread on modern browsers, though there is often some difference in the way some pickers are displayed on desktop. Mobile browsers are relatively consistent in showing the right keyboard depending on the input type selected. For the most up to date information, check out the state of HTML5 Form Features on CanIUse.com or The Current State of HTML5 Forms from Wufoo.

New input types

HTML5 introduces a number of new input types. These new input types give hints to the browser about what type of keyboard layout to display for on-screen keyboards.

Many browsers provide built-in validation for some input types like email and url. On other elements, you can indicate a valid input format by providing a regular expression in the the pattern attribute. For more information, be sure to read the section on Validation.

Input Type Description
url For entering a URL. It must start with a valid URI scheme, (for example http://, ftp:// or mailto:).
tel For entering phone numbers. It does not enforce a particular syntax for validation, so if you want to ensure a particular format, you can use pattern.
email For entering email addresses. By default it will only take one, but if the multiple attribute is provided, a comma separated list of email addresses is valid.
search A text input field styled in a way that is consistent with the platform's search field.
number For numeric input, can be any rational integer or float value.
color For choosing colors.
range For number input, but unlike the number input type, the value is less important. It is displayed to the user as a slider control.
datetime For entering a date and time value where the time zone is provided as GMT.
datetime-local For entering a date and time value where the time zone provided is the local time zone.
date For entering a date (only) with no time zone provided.
time For entering a time (only) with no time zone provided.
week For entering a date that consists of a week-year number and a week number, but no time zone.
month For entering a date with a year and a month, but no time zone.

Validation

Data validation doesn’t just help to keep your data clean, but it also helps improve the user experience. For example, datalists can provide auto-complete in text boxes suggesting options to the user. Warnings can be displayed when the users response doesn’t match the expected format. The JavaScript validation APIs can provide custom validation logic and prompt users with easy to understand error messages when they’ve provided invalid data.

Remember: Even with client side input validation, it is always important to validate data on the server to ensure consistency and security in your data.

Validation constraint attributes

The pattern attribute

The pattern attribute specifies a regular expression used to validate an input field. For the purpose of the example, let's say a part number consists of three uppercase letters followed by four digits. The use of pattern ensure that the field value matches the correct format for a part number.

<input type="text" id="partNumber" pattern="[A-Z]{3}[0-9]{4}" />

The required attribute

If the required attribute is present, then the field must contain a value before the form can be submitted. For example, to make the part number in the previous example required, we’d simply add the required attribute.

<input type="text" required id="partNumber" pattern="[A-Z]{3}[0-9]{4}" />

The min, max and step attributes

For numeric input types like number or range, you can specify the minimum and maximum values, as well as how much they should each increment/decrement when adjusted by the slider or spinners.

<input type="number" id="qty" min="0" max="100" step="1" />

You can also use the min and max attributes on any of the date type inputs.

The maxlength attribute

The maxlength attribute can be used to specify the maximum length of an input or textbox and is useful when you want to limit the length of information that the user can provide. For example, if you want to limit a filename to 12 characters, you can use the following.

<input type="text" id="83filename" maxlength="12" />

The novalidate attribute

In some cases, you may want to allow the user to submit the form even if it contains invalid input. To do this, add the novalidate attribute to the form element. In this case, all pseudo classes and JavaScript APIs will still allow you to check if the form validates.

<form role="form" novalidate>
  <label for="inpEmail">Email address</label>
  <input type="email" id="inpEmail" placeholder="Enter email">
</form>

Validation constraint APIs

The constraint validation API gives you powerful tools for handling custom validation. The API allows you to do things like set a custom error, check whether an element is valid, and determine the reason that an element is invalid. The table below lists the new JavaScript APIs and properties that are available on input elements.

API Use
willValidate Property that returns true or false if the element is a candidate for validation.
validity Property that returns a ValidityState object representing the validity states of the element.
validationMessage Property that returns a string with the reason the object failed the validation test.
checkValidity() Returns true if the element satisfies all of it’s constraints, and false otherwise.
setCustomValidity() Sets a custom validation message and the customError property of the ValidityState object to true.

One good example of where you might use the JavaScript validation APIs is to verify that the user has provided the correct email address on a sign up form where they’re asked to enter it twice. For example, in the blur event for the second input, you would call the following check function:

var elem = document.getElementById("email_addr_confirm");
elem.addEventListener("blur", verifyEmail);

function verifyEmail(input) {
  input = input.srcElement;
  if (input.value != document.getElementById('email_addr').value) {
    // the provided value doesn’t match the primary email address
    input.setCustomValidity('The two email addresses must match.');
  } else {
    // input is valid -- reset the error message
    input.setCustomValidity('');
  }
}

See the article on Constraint Validation for further details and additional uses.

The invalid event

In addition to the JavaScript APIs, the invalid event is fired when checkValidity() returns false, allowing you to provide custom messages. For example you could set the innerTextof a sibling element to the validationMessage, providing users with more information about why the input validation failed.

input.addEventListener("invalid", function(evt) {
  var elem = evt.srcElement;
  elem.nextSibling.innerText = elem.validationMessage;
});
Be careful when showing users the validationMessage - it’s often written in a way that makes sense to a developer but won’t make sense to a non-technical user.

The datalist element

The datalist element isn't an input type, but a list of suggested input values to associated with a form field. It lets the browser suggest autocomplete options as the user types. Unlike select elements where users must scan long lists to find the value they’re looking for, and limiting them only to those lists, datalists provide hints as the user types.

<label for="inpChocType">Chocolates</label>
<input type="text" id="inpChocType" list="chocType">
<datalist id="chocType">
  <option value="white" />
  <option value="milk" />
  <option value="dark" />
</datalist>

Remember: the datalist values are provided as suggestions, and users are not restricted to the suggestions provided.

Other new form attributes

Several other common form features are provided by new attributes that would have previously required additional code.

The autocomplete attribute

There may be cases where you don’t want the browser to automatically fill in data based on users past entries. You may want to use this in fields like one-time passwords, pin numbers or password hints. In this case, you can add the autocomplete="off" to either the form element or an individual element.

<input type="number" id="pinNum" min="0" max="9999" autocomplete="off" />

The autofocus attribute

On some forms, like the Google home page for example, you want the focus to immediately jump to a specific input so that the user can quickly begin using the form. While there are JavaScript helpers to do this, they can sometimes be annoying when they move focus after you’ve already started typing. Instead, you can use the autofocus attribute on an input element to specify that element as the primary form element.

<input type="text" id="partNum" pattern="[A-Z]{3}[0-9]{4}" autofocus />

The placeholder attribute

The placeholder attribute provides a hint to the user about what’s expected in the input by displaying its value as light text until the element gets focus. The browser automatically handles blank values, dirty inputs and other input states that would previously have to be special cased in JavaScript.

<input type="text" id="partNum" pattern="[A-Z]{3}[0-9]{4}" placeholder="XXX9999"/>

Styling with CSS3

HTML5 also introduces a number of new pseudo-classes that can be used to style inputs based on their value or attributes, making it easier for users to understand if they’ve filled the form out properly before trying to submit it.

  • :valid and :invalid - explicitly sets the style for an element when the input is valid/invalid.
  • :required and :optional - sets the style for elements that are required or optional.
  • :in-range and :out-of-range - styling for elements that support the min and max attribute

The example below sets the outline of the box to be red when the user has provided invalid input, and to attract their attention, makes the text bold when the field has focus.

input:invalid {
  outline: 2px solid red;
}
input:focus:invalid {
  color: red;
}

Validation happens immediately as the user types, and it’s possible they’ll see the invalid style while typing. To prevent this, you can set the style to something else, like the example below.

input:not(:focus):invalid {
  outline: 2px solid red;
}
input:focus:invalid {
  outline: 2px solid blue;
}

Unfortunately this does mean that they won’t know the data entered is invalid until they move the focus away from that input.

New APIs for accessing field values

Beyond the constraint validation API, there are a few other new functions and properties that are helpful for input elements.

API Use
.stepUp()
.stepDown()
For numeric and date inputs, you can use the stepUp() and stepDown() functions to adjust the value to its next logical step.
.valueAsNumber Property that returns the value as a number, useful for numeric inputs instead of having to do parseInt(element.value, 10) or parseFloat(element.value, 10).
.valueAsDate Property that returns the value as a Date object, useful for date inputs instead of having to manually parse them.

The FormData Object

One of the enhancements to XMLHttpRequest is the introduction of the FormData object. With the FormData object, you can create and send a set of key/value pairs and, optionally, files using XMLHttpRequest. When using this technique, the data is sent in the same format as if you'd submitted it via the form's submit() method with the encoding type of multipart/form-data.

FormData gives you a way to create HTML forms on-the-fly using JavaScript, and then submit them using XMLHttpRequest.send(). Here's a simple example:

var formData = new FormData();
formData.append("part_num", "123ABC"); 
formData.append("part_price", 7.95);
formData.append("part_image", somefile)

var xhr = new XMLHttpRequest();
xhr.open("POST", "http://some.url/");  
xhr.send(formData);

You can also use FormData to add additional data to an existing form before submitting it.

var formElement = document.getElementById("someFormElement");
var formData = new FormData(formElement);
formData.append("part_description", "The best part ever!");

var xhr = new XMLHttpRequest();
xhr.open("POST", "http://some.url/");
xhr.send(formData);

Putting it all together

Try the demo and be sure to try it on a mobile device (http://goo.gl/nXbMQq)

Summary

With a trivial amount of additional work today, we can significantly reduce the amount of pain your users feel when filling out web forms. Simply using the appropriate input type and providing real time feedback about the data they’ve provided can make the difference between a completed transaction and a lost customer.

Resources

Comments

0