HTML5 Rocks

HTML5 Rocks

HTML5 Rocks

Tutorials

Making Forms Fabulous with HTML5

Supported browsers:

Opera supported IE unsupported Safari supported Firefox supported Chrome supported
Leave a comment

Introduction

Not many people get excited about forms, but HTML5 brings some big improvements, both for the developers creating them and for the users filling them out. New form elements, attributes, input types, browser-based validation, CSS3 styling techniques, and the FormData object make it easier and hopefully more enjoyable to create forms.

Browser support

At the time of writing, support for all the new form and input elements, attributes and types varies widely across browsers. Even among browsers that support a particular feature, the behavior can be different from one browser to the next. The state of HTML5 forms support is changing very quickly though, and continues to improve. At the time of writing, these charts were the most up-to-date I could find, and they detail the state of browser support for HTML5 forms.

An overview of what's new

New elements

HTML5 introduces 5 new elements related to input and forms.

Element Purpose Notes
progress Represents completion of a task. The progress element could represent the progress of a file being uploaded.
meter Represents a scalar measurement within a known range. The meter element could be used to represent something like a temperature or weight measurement.
datalist Represents a set of option elements that can be used in combination with the new list attribute for input to make dropdown menus. When the input with the associated datalist gets focus, a dropdown menu appears and contains the values from the datalist.
keygen A control for key-pair generation. When the form is submitted, the private key gets stored in the local keystore, and the public key is sent to the server.
output Displays the results of a calculation. An example use of the output element could be to display the sum of the values of two input elements.

New input types

HTML5 introduces 13 new input types. When viewed in a browser that doesn't support them, these input types fall back to text input.

Input Type Purpose Notes
tel For entering a telephone number. tel does not enforce a particular syntax, so if you want to ensure a particular format, you can use pattern or setCustomValidity() to do additional validation.
search To prompt users to enter text that they want to search for. The difference between search and text is primarily stylistic. Using an input type of search might result in the input field being styled in a way that is consistent with that platform's search fields.
url For entering a single URL. url is intended for entering a single, absolute URL, which represents a pretty wide range of values.
email For entering either a single email address or a list of email addresses. If the multiple attribute is specified, then multiple email addresses can be entered, separated by commas.
datetime For entering a date and time with the time zone set to UTC.
date For entering a date with no time zone.
month For entering a date with a year and a month, but no time zone.
week For entering a date that consists of a week-year number and a week number, but no time zone. An example of this format is 2011-W05 for the fifth week of 2011.
time For entering a time value with hour, minute, seconds, and fractional seconds, but no time zone.
datetime-local For entering a date and time with no time zone.
number For numerical input. Valid values are floating point numbers.
range For numerical input, but unlike number, the actual is not important. The implementation of the range control is a slider in most browsers that support it.
color For choosing color through a color well control. The value must be a valid lowercase simple color such as #ffffff.

New input attributes

HTML5 also introduces several new attributes for the input and form elements.

Attribute Purpose Notes
autofocus Focuses the input on the element when the page is loaded. autofocus can be applied to input, select, textarea, and button.
placeholder Gives the user a hint about what sort of data they should enter. The placeholder value is displayed in light text until the element gets focus and the user enters some data. It can be specified on input and textarea.
form Specifies one or more forms to which the input element belongs. By using the form attribute, the input elements can be placed anywhere on the page, not just within the form element. Also, a single input element can be associated with more than one form.
required A boolean attribute that means the element is required. The required attribute is helpful for doing browser-based validation without using custom JavaScript.
autocomplete For specifying that a field should not autocomplete or be pre-filled by the browser based on a user's past entries. The autocomplete attribute for fields like a credit card number or one-time password, which you don't want autocomplete. By default, autocomplete is in the on state, so if you want to disable it, set it to off.
pattern For validating an element's value against a regular expression. When using a pattern, you should also specify a title value to give the user a description of the pattern that's expected.
dirname For submitting the directionality of the control with the form. For example, if the user entered text data with right-to-left directionality and the input element contained the dirname attribute, then an indication of the right-to-left directionality would be submitted along with the input value.
novalidate For disabling form submission validation when specified on a form element.
formaction For overriding the action attribute on the form element. This attribute is supported on input and button elements.
formenctype For overriding the enctype attribute on the form element. This attribute is supported on input and button elements.
formmethod For overriding the method attribute on the form element. This attribute is supported on input and button elements.
formnovalidate For overriding the novalidate attribute on the form element. This attribute is supported on input and button elements.
formtarget For overriding the target attribute on the form element. This attribute is supported on input and button elements.

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);

Browser-based validation

Let's be honest. Validating form data is a pretty boring task, but you need to do it anyway. To do client-side form validation today, you probably write some custom JavaScript code or use a library to do things like check for valid inputs or ensure required fields are filled out before the form is submitted.

New input attributes like required and pattern used in combination with CSS pseudo-class selectors make it easier to write the checks and display feedback to the user. There are other advanced validation techniques that allow you to use JavaScript to set custom validity rules and messages or to determine if an element is invalid and the reason why.

The required attribute

If the required attribute is present, then the field must contain a value when the form is submitted. Here's an example of an input field for a required email address that ensures that the field has a value and that the value is a valid email address, as defined here.

<input type="email" id="email_addr" name="email_addr" required />

The pattern attribute

The pattern attribute specified a regular expression used to validate an input field. This example represents a required text input field for a part number. For the purpose of the example, let's say a part number consists of three uppercase letters followed by four digits. The use of required and pattern ensure that the field has a value and that the value matches the correct format for a part number. If the user hovers over the field, the message in the title attribute is displayed.

<input type="text" id="part" name="part" required pattern="[A-Z]{3}[0-9]{4}"
       title="Part numbers consist of 3 uppercase letters followed by 4 digits."/>

Building on the previous example, you can also outline the input field in red if an invalid part number is entered. To do that, add this CSS to put a red border around the input field if the value is invalid.

:invalid {
  border: 2px solid #ff0000;
}

The formnovalidate attribute

The formnovalidate attribute can be applied to input or button elements. If it's present, then form submission validation is disabled. Here's an example where submitting a form via the Submit button requires valid input, but submitting via the Save button does not.

<input type="text" id="part" name="part" required pattern="[A-Z]{3}[0-9]{4}"
       title="Part numbers consist of 3 uppercase letters followed by 4 digits."/>
<input type="submit" formnovalidate value="Save">
<input type="submit" value="Submit">

The constraint validation API

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. Here's an example that displays a custom error if the values in two fields do not match.

<label>Email:</label>
<input type="email" id="email_addr" name="email_addr">

<label>Repeat Email Address:</label>
<input type="email" id="email_addr_repeat" name="email_addr_repeat" oninput="check(this)">

<script>
function check(input) {
  if (input.value != document.getElementById('email_addr').value) {
    input.setCustomValidity('The two email addresses must match.');
  } else {
    // input is valid -- reset the error message
    input.setCustomValidity('');
  }
}
</script>

Putting it all together

Here's an example for a reservation request form that pulls together different input types, form validation, and CSS selectors and styling.

$99.00

This is the HTML and JavaScript for the form:

<form oninput="total.value = (nights.valueAsNumber * 99) + 
 ((guests.valueAsNumber - 1) * 10)">

  <label>Full name:</label>
  <input type="text" id="full_name" name="full_name" placeholder="Jane Doe" required>

  <label>Email address:</label>
  <input type="email" id="email_addr" name="email_addr" required>

  <label>Repeat email address:</label>
  <input type="email" id="email_addr_repeat" name="email_addr_repeat" required 
   oninput="check(this)">

  <label>Arrival date:</label>
  <input type="date" id="arrival_dt" name="arrival_dt" required>
  
  <label>Number of nights (rooms are $99.00 per night):</label>
  <input type="number" id="nights" name="nights" value="1" min="1" max="30" required>

  <label>Number of guests (each additional guest adds $10.00 per night):</label>
  <input type="number" id="guests" name="guests" value="1" min="1" max="4" required>

  <label>Estimated total:</label>
  $<output id="total" name="total">99</output>.00
  <br><br>

  <label>Promo code:</label>
  <input type="text" id="promo" name="promo" pattern="[A-Za-z0-9]{6}" 
   title="Promo codes consist of 6 alphanumeric characters.">

  <input type="submit" value="Request Reservation" /> 
</form>

<script>
function check(input) {
  if (input.value != document.getElementById('email_addr').value) {
    input.setCustomValidity('The two email addresses must match.');
  } else {
    // input is valid -- reset the error message
    input.setCustomValidity('');
  }
}
</script>

This is the CSS that goes with the form code:

:invalid { 
  border-color: #e88;
  -webkit-box-shadow: 0 0 5px rgba(255, 0, 0, .8);
  -moz-box-shadow: 0 0 5px rbba(255, 0, 0, .8);
  -o-box-shadow: 0 0 5px rbba(255, 0, 0, .8);
  -ms-box-shadow: 0 0 5px rbba(255, 0, 0, .8);
  box-shadow:0 0 5px rgba(255, 0, 0, .8);
}

:required {
  border-color: #88a;
  -webkit-box-shadow: 0 0 5px rgba(0, 0, 255, .5);
  -moz-box-shadow: 0 0 5px rgba(0, 0, 255, .5);
  -o-box-shadow: 0 0 5px rgba(0, 0, 255, .5);
  -ms-box-shadow: 0 0 5px rgba(0, 0, 255, .5);
  box-shadow: 0 0 5px rgba(0, 0, 255, .5);
}

form {
  width:300px;
  margin: 20px auto;
}

input {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  border:1px solid #ccc;
  font-size:20px;
  width:300px;
  min-height:30px;
  display:block;
  margin-bottom:15px;
  margin-top:5px;
  outline: none;

  -webkit-border-radius:5px;
  -moz-border-radius:5px;
  -o-border-radius:5px;
  -ms-border-radius:5px;
  border-radius:5px;
}

input[type=submit] {
  background:none;
  padding:10px;
}

Resources

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the Apache 2.0 License.