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.
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;
}
