Whether you want to book a flight, take care of your online banking, or enter a search term in Google, without forms, none of these services would be usable. Most of the elements for interactive forms have remained unchanged since HTML 2.0 arrived in 1995. On one hand this indicates that Tim Berners-Lee’s design showed great foresight; on the other hand there is now a huge need to catch up. The HTML5 specification devotes a large section to the topic of forms and will greatly facilitate any web designer’s work.
Even though browser support is not yet overwhelming at the time of this writing (so far, it’s only offered by Opera and the developer release of Google Chrome), the backward compatible syntax means that we can safely use the new form elements now.
The HTML5 specification enhances the input
element by allowing several more values for the type
attribute. The new types, for example, date
, color
, and range
, enable browser manufacturers to make user-friendly input elements available and also make it possible for the browser to ensure that the input is of the desired type. If a browser does not recognize the type
of the input
element, it will fall back on type=text
and display a text field, which is useful in any case. Even older browsers show this behavior, so there is nothing to stop us from using the new types right away.
The types for date and time will probably be the most useful. Currently, there are countless different versions of more or less successful JavaScript calendars available on the Internet. Entering a date comfortably, be it for booking a flight or a hotel room, or registering for a conference, is a problem that until now required manual work. Of course, JavaScript libraries, such as jQuery, offer ready-made calendars, but this function should really be supported by the browser directly.
At the time of this writing, there is only one desktop browser that includes a graphic input element for entering the date: Opera. In Figure 3.1 you can see the open calendar that will be displayed if you click on an input
element with the type date
. But let’s tackle things in order: Table 3.1 provides an overview of the new types; then you can see what they look like in the Opera browser in Figure 3.1.
tel
and search
are not significantly different from normal text fields. Both can contain character chains without line breaks. Even telephone numbers are not limited to numbers, because phone numbers often contain brackets or the plus symbol. For tel
, the browser could offer suggestions from the local address book, a situation that is particularly useful with cell phones. The search
type was introduced to allow the browser to make the search input consistent with the layout of the relevant platform. Mac OS X users, for example, are used to seeing search fields with rounded corners.
In addition to suggesting options, the browser can also check the syntax for url
and email
. Because there are concrete rules for e-mail addresses and Internet addresses in the form of URLs, the browser can already provide feedback on possible mistakes during input (more on this topic in section 3.4, Client-side Form Validation).
Let’s take a closer look at the date and time formats. datetime
contains date and time information; the time zone is always set to UTC. The specification states that the browser can allow the user to select another time zone, but the value of the input
element has to be converted to UTC. The rules for time information in the datetime
attribute of the time
element, which we discussed in section 2.7.2, The “time” Element, apply here as well—with the only exception that the string always has to end in a Z
, the identifier of UTC.
With date
and month
, the time and time zone are omitted. As defined in the specification, the date
must be a valid day within the selected month, also taking into account leap years. Year, month, and day must be separated by a minus character; the year has to be at least four digits long and greater than 0
. So dates before Christ (B.C.) cannot be represented in HTML5, in contrast to the somewhat more extensive international standard ISO 8601.
The type week
is represented as a week in a year, and it is mandatory that the week be preceded by the year. Year and week are once again separated by a minus character. To ensure that there is no confusion with month
, the week must be preceded by the character W
.
datetime-local
works the same way as the already described datetime;
the only difference is that there is no timezone specified.
Opera uses a calendar window for selecting the date; the time can be entered manually or changed via arrow keys (refer to Figure 3.1).
The types number
and range
require input that can be converted to a numerical value; the notation of floating-point numbers (for example, 2.99792458E8
) is valid. Regarding the type range
, the specification states that the exact value is not relevant; this type indicates a range of numbers, not an exact number, and the user can easily enter it with a slider bar. Both Opera and WebKit-based browsers, such as Safari or Google Chrome, use a slider bar to represent this type (refer to Figure 3.1 and see Figure 3.2).
Once again the developers of Opera lead the way by being the first to program a graphical input option for the color
element. As you can see in Figure 3.1, Opera (version 11 and later) offers a rectangular field with a choice of frequently used colors. You can also bring up a color picker along the lines of those you see in image-editing programs. Sadly, this input element is still not implemented in the other browsers.
The value of the input
element must contain the 8-bit RGB values in hexadecimal notation preceded by a #
character. The color blue, for example, would be written as #0000ff
.
Enough with the theory: Our first example shows you the new elements, one below the other. Because that’s not very challenging, we will also test each element’s function. The trick is that the browser will set the type of an unknown element to text
, and we can then evaluate those properties in JavaScript:
<script>
window.onload = function() {
inputs = document.getElementsByTagName("input");
for (var i=0; i<inputs.length; i++) {
if (inputs[i].type == "text") {
inputs[i].value = "not available";
}
}
}
</script>
As soon as the web page has finished loading, a loop runs over all input
elements to analyze their type
attributes. If the type
attribute corresponds to the standard type text
, its value is set to not available. The HTML code for the new input
elements looks like this:
<fieldset>
<legend>New input types</legend>
<p><label for=tel>tel</label>
<input type=tel id=tel name=tel>
<p><label for=search>search</label>
<input type=search id=search name=search>
<p><label for=url>url</label>
<input type=url id=url name=url>
<p><label for=email>email</label>
...
In Figure 3.3 you can see what the result of this test looks like on an Android cell phone. The system’s WebKit-based browser (left) pretends to know the types tel
, search
, url
, and email
but does not really help when it comes to entering the telephone number via the keyboard (center). Opera Mobile in version 10.1 beta (right) supports url
and email
, plus the date
and time
types.
That is a rather disappointing result for the otherwise so modern Android browser. Results look slightly better on the iPhone: At least the smartphone adapts the software keyboard, displaying a numeric keyboard when you try to enter a phone number and adding the @
character on the keyboard for the input
type email
.
This test works even better with BlackBerry, the operating system of the popular line of smartphones produced by the Canadian manufacturer Research in Motion (RIM). As you can see in Figure 3.4, the BlackBerry supports both tel
and number
plus date types, and the latter in particular are represented in very attractive graphics. Under the hood we find WebKit at work: The software was expanded to include these functions.
Apart from new elements and many new types for the input
element, HTML5 also offers several new attributes for form elements.
Years ago, Google surprised many users with a simple trick that made searching much more convenient: When the page was loaded, the cursor was automatically positioned in the search field. The user was able to enter the search term directly without having to first activate the input box by clicking with the mouse. Previously, this was done with a short snippet of JavaScript; in HTML5 you can now do it with the autofocus
attribute:
<input type=search name=query autofocus>
As with all boolean attributes, you can write this attribute as autofocus="autofocus"
(see Chapter 2, section 2.7.2, The “time” Element). The specification states that only one element in a web page can contain the autofocus
attribute.
Older browsers do not have a problem with autofocus
, because they simply ignore the unknown attribute. Of course, you only get the benefit of user friendliness with new browsers.
Usability of HTML forms can be further improved with the new placeholder
attribute:
<p><label for=email>Your e-mail address:</label>
<input type=email name=email id=email
placeholder="[email protected]">
<p><label for=birthday>Your date of birth</label>
<input type=date name=birthday id=birthday
placeholder="1978-11-24">
The value of placeholder
can give the user a quick hint about how to fill in the field, but it should not be used as an alternative to the label
element. It is particularly useful for fields where a certain data entry format is expected. The browser displays the hint text within an inactive input field. As soon as the field is activated and is focused, the text is no longer displayed (see Figure 3.5).
required is a boolean attribute, and its name already says everything about its function: A form element that this attribute is assigned to must be filled in. If a required
field remains blank when the form is sent, it does not fulfill the requirements and the browser must react accordingly. You will find more information on this in section 3.4, Client-side Form Validation.
The input
element has not only been enhanced with new types (section 3.1, New Input Types), but also with new attributes that enable easier handling of forms (see Table 3.2).
We will come across the list
attribute again in section 3.3.3, Lists of Options with “datalist”. It refers to the datalist
element, which offers possible entries as suggestions.
min
, max
, and step
are not only suitable for numeric fields, but these attributes can also be used for entering the date and time:
<p><label for=minMax>Decimal number between 0 and 1:</label>
<input type=number name=minMax id=minMax
min=0 max=1 step=0.1>
<p><label for=minMaxDate>Date in week steps:</label>
<input type=date name=minMaxDate id=minMaxDate
min=2010-08-01 max=2010-11-11 step=7>
<p><label for=minMaxTime>Time in hour steps:</label>
<input type=time name=minMaxTime id=minMaxTime
min=14:30 max=19:30 step=3600>
In browsers that support the input
type number
, the first input
element (id=minMax
) is increased each time by a value of 0.1
. This works by clicking the arrow keys at the end of the text field or by pressing the arrow keys on the keyboard. The element with the ID minMaxDate
jumps forward seven days each time. Opera only displays those days in the calendar as active that correspond to the week cycle. For setting this element, Google Chrome offers the same navigation as with the input
type number
: two arrow keys that set the date forward or backward seven days. In the third input
element in this example, the step size is set to 3600;
this causes the time to be set one hour forward or one hour backward. Although the specification states that the input elements for time usually work in minutes, both Opera and Google Chrome interpret this data as seconds.
We are all familiar with multiple selection from copying files; now this option exists for browsers as well. If you wanted to load several files on a website at once, you previously had to provide an input
field for each file. The multiple
attribute allows for the marking of several files in the file dialog. The multiple
option was always intended for the select
element; using it for input fields of the type email
is new. But as yet (at the time of this writing), none of the commonly used desktop browsers can implement this function for email
types.
Modern browsers have a function that allows them to save form data to help the user fill in forms when the form is revisited. This prefilling can be very useful but would be undesirable for security-sensitive input fields (the specification mentions the activation codes for nuclear weapons as an example). The autocomplete
attribute was introduced to allow web developers to govern this behavior. If an element has the attribute autocomplete="off"
assigned to it, that means the information to be entered is confidential and should not be saved in the browser. If the form element does not state if autocomplete
should be switched on or off, the default setting is to display suggestions. The autocomplete
attribute can also be applied to the whole form by assigning it to the form
element.
The new pattern
attribute allows for very flexible input verification. You can specify a regular expression against which the form field will be checked for a match. Regular expressions are very powerful but unfortunately not a very easy method of parsing strings. Imagine you are looking for a character string starting with an uppercase character followed by any number of lowercase letters or numbers and ending in .txt
. Finding it is no problem at all with a regexp (short for regular expression):
[A-Z]{1}[a-z,0-9]+.txt
Note
An introduction to regular expressions would be far beyond the scope of this chapter, so let’s assume for now that you have basic knowledge of regular expressions when you read the following section. If you are looking for a brief online introduction to regular expressions, Wikipedia is a good starting point: Browse to http://en.wikipedia.org/wiki/Regular_expression. The website http://www.regexe.com gives you the chance to try regular expressions online.
When using regular expressions with the pattern
attribute you need to remember that the search pattern always has to apply to the field’s entire content. The specification also suggests using the title
attribute to give the user a hint regarding the input format. Opera and Google Chrome display this kind of information as a tool tip as soon as the mouse pointer hovers over the field. After all this theory, here is a brief example:
<p><label for=pattern>Your nickname:</label>
<input type=text pattern="[a-z]{3,32}"
placeholder=""johnsmith" name=pattern id=pattern
title="Only lower case, please; min. 3, max. 32!">
The guideline for the pattern
attribute specifies that the character string can only contain characters between a
and z
(in lowercase,[a-z]
) and that there are at least 3
and at most 32
characters. Special characters or umlauts are not allowed, which can be useful for a user name as in the preceding example. If you want to include certain special characters, for example, the umlauts in the German language, you need to include them in the group: [a-zäöüß]
. In section 3.4, Client-side Form Validation, you can find out what happens if the validation fails.
In addition to the new input types and the new attributes mentioned earlier, the specification also includes new elements for forms. We will discuss these in the next section. The elements meter
and progress
create graphical objects that previously could only be achieved with more or less complicated tricks. Suggestions for text input are offered by datalist
, and output
provides a placeholder for the results of calculations. The keygen
element has been circulating through the World Wide Web for a long time but has only reached standardization with HTML5.
The meter
element is used to graphically represent a scalar measurement within a known range. Think, for example, of the fuel gauge in your car: The needle shows the current level of fuel in your tank as somewhere between 0 and 100 percent. Previously, such graphic representations were usually coded in HTML with nested div
elements, a rather inelegant solution for which the div
element was probably not intended. A status display can also be displayed graphically, as a picture, through free web services, such as the Google Chart API. You can see all of these options in the example that follows.
Using the meter
element is very simple: You set the desired value via the value
attribute; all other attributes are optional. If you do not set a min
and max
value, the browser will use 0 and 1 for these attributes. So, the following meter
element shows a half-full element:
<meter value=0.5></meter>
Apart from value
, min
, and max
are also the attributes low
, high
, and optimum
—values that the browser can incorporate into the display. Google Chrome (at the time of this writing, the only browser apart from Opera that is able to represent the meter
element), for example, displays the normally green bar in yellow if the optimum
value is exceeded.
In the following example you can see a graphic representation, showing the percentage of the current year that has already passed. The website presents a visualization of the output in four different ways: as text with a value in percent, using the new meter
element, via nested div
elements, and as graphics produced by the online service of Google’s Chart API. You can see the result in Figure 3.6.
The HTML code for this example contains the still empty elements, which are filled via JavaScript:
<h2>Text</h2>
<p><output id=op></output>
% of the year has passed.</p>
<h2>The new <span class=tt>meter</span> element</h2>
<meter value=0 id=m></meter>
<h2>Nested <span class=tt>div</span> elements</h2>
<div id=outer style="background:lightgray;width:150px;" >
<div id=innerDIV> </div></div>
<h2>Google Chart API</h2>
<img id=google src="">
<p id=googleSrc class=tt></p>
For the text output, we use the output
element introduced in section 3.3.5, Calculations with “output”. But first the current date is generated in JavaScript, and the meter
element is initialized:
var today = new Date();
var m = document.getElementById("m");
m.min = new Date(today.getFullYear(), 0, 1);
m.max = new Date(today.getFullYear(), 11, 31);
// m.optimum = m.min-m.max/2;
m.value = today;
The variable today
contains the number of milliseconds since the start of the UNIX epoch (on 1.1.1970). To make sure our meter
element gets a sensible scale, we set the min
value to January 1 of the current year and the max
value accordingly to December 31. The value of the meter
element is set in the last line of the listing; now the graphical representation is complete. If you activate the optimum
value (in this case the middle of the year), which we left out, you will see the display change depending on whether you call the script in the first or second half of the year. The new element is wonderfully simple to use.
Let’s now move on to the other elements on our HTML web page. We want to assign the percentage of days passed to the output
element tagged with the ID op
. With Math.round()
, we round up the percentage to the nearest number before the comma, which is plenty accurate enough for our example:
var op = document.getElementById("op");
op.value =
Math.round(100/(m.max-m.min)*(m.value-m.min));
var innerDIV = document.getElementById("innerDIV");
innerDIV.style.width=op.value+"%";
innerDIV.style.background = "green";
The rest of our example has nothing to do with new HTML5 techniques, but we still want to explain it for the sake of completeness. The nested div
elements should also be filled with the percentage value. The idea behind this is simple: A first div
area is defined in HTML with a fixed width (here, 150px
). Nested into this element, another div
element is displayed as filled with a green background color along the width of the calculated percentage value—a simple yet very effective trick. To round things off, we also want to include the Google Chart API. To use the online service, you have to specify the chart size (chs
, in our case 200×125
pixels), the chart type (cht
, here, gom
, Google-O-Meter), and the chart data (chd
, here, the percentage value op.value
):
var google = document.getElementById("google");
google.src =
"http://chart.apis.google.com/chart?chs=200x125&cht=gom&chd=t:"+op.
value;
var gSrc = document.getElementById("googleSrc");
gSrc.innerHTML = google.src;
progress
works in a similar way as the meter
element discussed previously except that it represents the completion progress of a task. Such tasks could, for example, be file uploads by the user or downloads of external libraries required by an application.
To give you a quick example, we do not really want to upload any files or download a lot of data; it is sufficient to set ourselves a task and fulfill it 100 percent. Our following example defines ten input elements of the type checkbox
, and as soon as they are all activated, we want the progress bar to show 100 %:
<h1>Please activate all the checkboxes</h1>
<form method=get>
<input type=checkbox onchange=updateProgress()>
<input type=checkbox onchange=updateProgress()>
<!-- and 8 more -->
<p>
Progress: <progress value=0 max=10 id=pb></progress>
</form>
The progress
element is initialized with a value of 0
and a maximum value of 10
. As soon as an input element is activated, it calls the function updateProgress()
, which looks like this:
function updateProgress() {
var pb = document.getElementById("pb");
var ip = document.getElementsByTagName("input");
var cnt = 0;
for(var i=0; i<ip.length; i++) {
if (ip[i].checked == true) {
cnt++;
}
}
pb.value = cnt;
}
The variable ip
contains a NodeList with all input
elements. Each of these elements is tested in the for
loop for its condition. If it is activated (checked == true
), the counter variable cnt
increases by 1. To finish, the value of the progress
element is set to the value of the counter variable.
One long-awaited new function for forms is a drop-down menu to which you can add your own entries. Because the well-known select
element is limited to the values specified as option
elements, web developers used to come up with various JavaScript tricks to add expandable selection lists to text fields.
The HTML5 specification now has a very elegant solution to this problem. The new datalist
element was defined to function as a container for the already familiar option
element. Now we can assign to each input
element a datalist
element that displays the selection options when needed. Browsers that do not support the datalist
element will only display the empty text field.
Listing 3.1 shows the use of the new element. The input
element is defined by the type text
, and the attribute list
refers to the id
of the datalist
element (in this case, homepages
). When the page is loaded, the autofocus
attribute positions the cursor automatically inside the text field (see section 3.2.1, Focusing with “autofocus”) and ensures, at least with the Opera browser, that the selection list appears (see Figure 3.7).
For the option
elements within the datalist
, you just need to fill the value
attribute. Further attributes and a text node are possible but not required for this use. If the user clicks the Submit button, the content of the text field is prefixed with the character string http://
and the browser is redirected to the resulting URL (window.location
):
<form>
<p>
<label for=url>Goto</label>
http://<input type=text id=url name=homepage
list=hompages autofocus>
<datalist id=hompages>
<option value=www.google.com>
<option value=html5.komplett.cc/welcome>
<option value=slashdot.org>
<option value=wired.com>
</datalist>
<input type=submit
onclick="window.location =
'http://'+document.getElementById('url').value;
return false;" >
</form>
If you want to equip older browsers with a selection list without duplicating the HTML code, you can fall back on the following trick. Because browsers supporting the datalist
element ignore an enclosed select
element, they display the new HTML5 select element. Older browsers, however, display a selection list for the text field with predefined links, which will be inserted into the text field when the selection is changed.
As you can see in Listing 3.2, we need to add a text node to the option
elements because the “old” select
element does not show the content of the value
attribute but instead shows the text:
<datalist id=hompages>
<select name=homepage
onchange="document.getElementById('url').value =
document.forms[0].homepage[1].value" >
<option value=www.google.com>www.google.com
<option
value=html5.komplett.cc/welcome>html5.komplett.cc/welcome
<option value=slashdot.org>slashdot.org
<option value=wired.com>wired.com
</select>
</datalist>
The onchange
event within the select
element inserts the current text of the selection menu into the text box (see Figure 3.8).
The keygen
element has a long history in the Mozilla Firefox browser (included since version 1.0), but Microsoft still expressed great concern regarding the implementation in HTML5. keygen
is used to generate cryptographic keys, which sounds complicated, and unfortunately, it is just as complicated as it sounds.
Simply put, the idea behind this element is this: The browser creates a pair of keys, one a public key and the other a private key. The public key is sent off with the other form data and is then available to the server application, whereas the private key remains saved in the browser. After this exchange of keys, the server and browser can communicate in encryption without SSL certificates. This sounds like a practical solution for those pesky self-signed certificates, which browsers keep complaining about, but sadly it is not, because the identity of the server can only be verified through a certificate that has been signed by a trustworthy authority, the Certificate Authority (CA).
So if keygen
cannot replace SSL, what should the new element be used for? As explained in the Mozilla documentation, the keygen
element helps create a certificate that the server can sign (signed certificate). To make this step totally secure, it is usually necessary for the applicant to appear personally before the authority. Because the issuing of signed certificates is a task for experts, we will briefly describe this element and its attributes.
The following short HTML document creates a keygen
button:
<!DOCTYPE html>
<meta charset="utf-8">
<title>keygen Demo</title>
<form method=post action=submit.html>
<keygen id=kg challenge=hereismychallenge name=kg>
<input type=submit>
</form>
In addition to the familiar attributes, such as autofocus
, disabled
, name
, and form
, the keygen
element has two special attributes: keytype
and challenge
. keytype
in particular is interesting because the browser uses this entry to decide if it supports this element’s function. Currently, there is only one valid keytype
, which is rsa
, a cryptographic system developed in 1977 at the Massachusetts Institute of Technology (MIT). If no keytype
is specified (as in the preceding example), rsa
is used as the default value. The specification also states that a browser does not have to support any keytype
at all, which is probably because of Microsoft’s veto against this element. The optional challenge
attribute increases security during the key exchange. For further information, please refer to the links in the note at the end of this section.
If the browser supports the RSA key generation, it can offer a selection list to allow the user to select the length, and consequently the security, of the key (see Figure 3.9).
Figure 3.10 shows the result after the form has been sent: The POST
variable kg
contains the public key required for encryption (here, rendered in the extremely useful Firefox add-on Firebug).
Note
If you have not had much previous experience with cryptography but would like to find out more, Wikipedia is always a good starting point. Check out http://en.wikipedia.org/wiki/Public_key_infrastructure and http://en.wikipedia.org/wiki/Challenge-response_authentication.
“The output
element represents the result of a calculation.” That is the very short explanation in the HTML5 specification, and you will find exactly the same text on most websites describing the new element. It all sounds very sensible, but what kind of calculations are we dealing with? Why do we need a special element for them?
As a general rule, these are calculations resulting from input fields on a website. An example familiar to most people would be an electronic shopping cart where the quantity for each product can be entered in an input
field. Via the optional for
attribute, you can determine which fields to include in the calculation. One or more id
attributes of other fields in the document are referenced in the process.
To test the output
element, we will program one of these little shopping carts for three different products. The quantity of each of these products can be changed via an input field. At the same time, the total number of items and the total price are displayed under the shopping cart. Figure 3.11 shows a shopping basket with five items.
The code for our example can be explained quickly and simply: To update the output
elements for each change in quantity, we use the form’s oninput
event:
<form oninput="updateSum();">
<table>
<tr><th>Product<th>Price (US$)<th>Item number
<tr><td>Keyboard<td class=num id=i1Price>39.50<td>
<input name=i1 id=i1 type=number min=0 value=0 max=99>
<tr><td>Mouse<td class=num id=i2Price>26.30<td>
The output
elements are defined after the table with the products and refer to the IDs of the input
fields via the for
attribute:
<p>Your shopping cart contains <output name=sumProd for="i1 i2 i3"
id=sumProd></output> items. Total price:
<output name=sum for="i1 i2 i3" id=sum></output> US$.
In the JavaScript code, a loop runs over all input
elements, adding the quantities and calculating the total price:
function updateSum() {
var ips = document.getElementsByTagName("input");
var sum = 0;
var prods = 0;
for (var i=0; i<ips.length; i++) {
var cnt=Number(ips[i].value);
if (cnt > 0) {
sum += cnt * Number(document.getElementById(
ips[i].name+"Price").innerHTML);
prods += cnt;
}
}
document.getElementById("sumProd").value = prods;
document.getElementById("sum").value = sum;
}
We get the product price directly from the table by using the innerHTML
value of the relevant table column and converting it to a number with the JavaScript function Number()
. The same applies to the value in the input
field (ips[i].value
), because without this conversion, JavaScript would add up the character strings, which would not produce the desired results. The calculated values are then inserted into the value
attributes of the output
elements.
One of the advantages of the new elements and attributes in forms is that the user can now enter data much more easily (for example, choose the date from a calendar). Another great advantage is the option of checking the form contents before the form is submitted and alerting the user of any mistakes. You might say that kind of checking is rather old hat because it has been around for years. That is true, but until now this step always had to be done via JavaScript code that you had to program. Thanks to jQuery and similar libraries, this task has become much easier and the code is more manageable, but you still must depend on an external library.
With HTML5, this situation changes fundamentally: You define the parameters of the input fields in HTML, and the browser checks whether the fields have been filled in correctly. That is a big step forward and makes many lines of JavaScript code redundant. This tiny example will convince you:
<form method=get action=required.html>
<p><label>Your e-mail address:
<input type=email name=email required></label>
<p><input type=submit>
</form>
Figure 3.12 shows what will happen if you submit the form in the preceding listing without specifying an e-mail address. Opera displays the error message: This is a required field. If you have set the Opera user interface to another language, the error message appears in the relevant language. Of course, you can also adapt these error messages with JavaScript; more on this in section 3.4.3.
But that is not all: The field is defined as the type email
, so Opera also returns an error message if an invalid e-mail address is entered; for example, Please enter a valid email address (see Figure 3.13).
WebKit-based browsers, such as Google Chrome or Safari, currently support the validation but do not display an error message. They place a border around the invalid field and position the cursor in the field to at least provide some indication that something is not quite right.
Note
Despite all the euphoria about client-side validation of form input, you should not forget that this step cannot replace server-side control. A potential attacker can bypass these mechanisms with very little technical effort.
During form validation, elements with an invalid content trigger the event invalid
. We can use this to react individually to incorrect values:
window.onload = function() {
var inputs = document.getElementsByTagName("input");
for (var i=0; i<inputs.length; i++) {
inputs[i].addEventListener("invalid", function() {
alert("Field "+this.labels[0].innerHTML
+" is invalid");
this.style.border = 'dotted 2px red';
}, false);
}
}
After loading the page, a list of all input
elements is generated (as in the example in section 3.3.5). An event listener is added to each element and deals with the error. In our example it opens an alert
window, and the element is marked with a red-dotted border. The label of the input
element is used as text in the alert
window.
This approach is not ideal in forms with many input fields. The user must click the OK button for each incorrect input and then find the appropriate field in the form and fill in the details again. Sometimes, it would be more useful if the user could be notified immediately of invalid input while filling in the field. We will try this in the next section.
To trigger the validation of an input
element, the checkValidity
function for that element is called. But you can also start “manually” what would normally happen when the form is submitted:
<input type=email name=email
onchange="this.checkValidity();">
If you enter an invalid e-mail address and move away from the input field (either with the Tab key or by clicking elsewhere in the browser), the browser (currently, at least in Opera) returns an error message right away (refer to Figure 3.13). Error handling becomes even more elegant if we attach a function for checking input to the onchange
event of all input
elements:
window.onload = function() {
var inputs = document.getElementsByTagName("input");
for (var i=0; i<inputs.length; i++) {
if (!inputs[i].willValidate) {
continue;
}
inputs[i].onchange = function() {
if (!this.checkValidity()) {
this.style.border = 'solid 2px red';
this.style.background = '';
} else {
this.style.border = '';
this.style.background = 'lightgreen';
}
}
}
}
The familiar loop runs over all input
elements, checking first whether the element is available for validation. If willValidate
does not return the value true, the loop continues with the next element. Otherwise, an anonymous function is assigned to the onchange
event, calling the checkValidity
function. this
within the anonymous function refers to the input
element. If the validity check fails, the element is surrounded with a red border; otherwise, the element’s background is colored light green. Remember to reset the background color and border to an empty character string to make sure the browser sets the formatting back to the default value after the user has corrected an incorrect input. In Figure 3.14 you can see how the checkValidity
function generates an error message as a result of incorrect time input.
If you would like to make error handling more interactive, you can use the new HTML5 oninput
event instead of the onchange
event. Unlike onchange
, which is triggered when the field no longer has the focus, oninput
is activated after every changed character. The oninput
event now does what you previously had to program somewhat laboriously via the keyboard events keyup
and keydown
. Another advantage of oninput
is that the event listener needs to be attached only once to the whole form, not to each input
element. So in our preceding example, you could do without all the JavaScript code and change the form definition as follows:
<form method=get oninput="this.checkValidity();"
action=checkValidity.html >
This means you forgo changing the borders and background color, but you significantly shorten the source code. An immediate reaction to each keystroke can be very helpful in some cases, but when filling in a form field, it is usually enough if the content is checked after the field has been fully completed.
If you feel that all the error handling methods introduced earlier are still not quite enough, you can also program your own function for checking content. In the following example, we define an input field with the type email
, which ensures that the browser will check for a valid e-mail address. Additionally, we want to specifically exclude three e-mail domains:
var invalidMailDomains = [
'hotmail.com', 'gmx.com', 'gmail.com' ];
function checkMailDomain(item) {
for (var i=0; i<invalidMailDomains.length; i++) {
if (item.value.match(invalidMailDomains[i]+'$')) {
item.setCustomValidity('E-mail addresses from '
+invalidMailDomains[i]+' are not accepted.'),
} else {
item.setCustomValidity(''),
}
item.checkValidity();
}
}
Each element in the array invalidMailDomains
is compared to the value of the input
element. The JavaScript function match()
works with regular expressions, which is why we add a $
symbol to the domain name, to indicate the end of the character string. If the character strings match, the setCustomValidity
function is called and displays the appropriate error message. If it is not a domain name from the array, setCustomValidity()
is called with an empty character string. Internally, this attaches the variable validationMessage
to the input
element, which Opera then displays (see Figure 3.15). The concluding call of the checkValidity
function triggers the validity check and leads to the aforementioned error message.
Table 3.3 shows a summary of all input
attributes and validity functions available for validity checks, and the scenarios where they occur.
Now that we have spent so much time discussing error handling, we will tell you how you can sneak past all the rules with the attribute formnovalidate
. At first it may seem a little strange to simply disregard all the laboriously defined rules and just submit the form without validation. The specification offers a brief explanation that quickly solves the mystery. The typical application for skipping the validity check is a form that the user cannot or does not want to complete in one go. By adding the formnovalidate
attribute to a submit
button, the content that has been entered so far can be saved for later.
Note
If you submit a form with formnovalidate
, the fields already completed are sent to the server. The server application is responsible for potentially saving the data temporarily.
Imagine, for example, that you want to fill in a support form for your faulty digital camera. After spending ages filling in all the details about the error that has occurred, the website asks you for the camera’s serial number. Because you do not have the camera at hand and you do not want to lose all the information you have already entered, you click the Save button and can then calmly go looking for your camera. This button is defined as follows:
<p><input type=submit formnovalidate
value="Save" name=save id=save>
The following example will fully illustrate the idea of the support form.
In this example, the previously introduced new elements and attributes are used in a form. A form of this kind could, in an expanded state, be used on the website of an electronics dealer.
Initially, the client is asked to supply personal details (in this example just the name, an e-mail address, and a telephone and fax number). The second part of the form concerns the product’s technical data and defect. The bottom part of the webpage shows a progress bar that is meant to encourage the user to complete the form (see Figure 3.16).
The HTML code for the form starts by loading an external JavaScript file and the already familiar call window.onload
:
<script src="support.js"></script>
<script>
window.onload = function() {
initEventListener();
}
</script>
The initEventListener
function runs through all input
elements and assigns an anonymous function to the onchange
event, checking the corresponding element for its validity:
function initEventListener() {
var inputs = document.getElementsByTagName("input");
for (var i=0; i<inputs.length; i++) {
if (!inputs[i].willValidate) {
continue;
}
inputs[i].onchange = function() {
this.checkValidity();
}
}
}
The event listener is only added if the element can check validity. In our example the two buttons for submitting or saving do not have the option to check validity and therefore do not get an onchange
event. As explained earlier, checking the individual form fields after they have been filled in is more convenient than checking the entire form with the oninput
event.
To improve the form’s user friendliness, we want to emphasize the elements marked as required
to make it immediately clear to the user which are the most important fields. Fortunately, we do not have to add an extra style to each element. CSS3 gives us the new selector :required
, which is intended for exactly this case. The following instruction places an orange border around all required elements:
:required { border-color: orange; border-style: solid; }
The definition of the individual input
fields does not contain any great surprises. E-mail address and phone number have their own types and are required; the date when the defect occurred has the type date
and can therefore be selected from a calendar window. The two-column layout in the upper part of the webpage is achieved via adjacent div
elements. We still want users who jump to the next field using the Tab key to fill in the form from top to bottom and not, as HTML logic would suggest, first fill in the left and then the right column. We can achieve this with the tabindex
attribute, which means that pressing the Tab key in a field will move the cursor to the field with the next higher tabindex
value:
<div style="float:left">
<p><label>Your name
<input tabindex=1 type=text required autofocus
placeholder="John Smith" name=name></label>
<p><label>Your e-mail address
<input tabindex=3 type=email name=email required></label>
</div>
<div style="float:left;margin-left:10px;">
<p><label>Telephone number
<input tabindex=2 type=tel name=tel required></label>
<p><label>Fax number
<input tabindex=4 type=tel name=fax></label>
</div>
Now the code gets more exciting with the textarea
fields. HTML5 does not make many changes to this type. But as you can see in Figure 3.16, each text field now has a small graphic display above it, showing how many characters you can still type into this field. You probably realized it right away: It’s done with the new meter
element, which you already know from section 3.3.1, Displaying Measurements with “meter”:
<p><label>Error message
<textarea placeholder="Lens error. Camera restart."
name=errmsg required rows=5 cols=50
title="up to 200 characters">
</textarea></label><meter value=0 max=200
tabindex=-1></meter>
The meter
element is initialized with a maximum value of 200
, exactly the value specified as maximum in the title
attribute of the textarea
. If a user enters more characters than the maximum allowed, the meter
element turns red, indicating that the text entered is too long. The browser will still submit all the text, because we have not limited the textarea
. So this is more a hint rather than a strict requirement. The JavaScript function for updating the meter
elements is updateTAMeters()
and is executed for all textarea
s:
function updateTAMeters() {
var textfs = document.getElementsByTagName("textarea");
for(var i=0; i<textfs.length; i++) {
textfs[i].labels[0].nextSibling.value =
textfs[i].textLength;
}
}
The advantage of the loop is that we can now add any number of textarea
elements, and as long as they have a meter
element, they will be updated automatically. To achieve this, we need to resort to a DOM trick: The code printed in bold in the preceding listing accesses the DOM function nextSibling
, a reference to the next element. Let’s revisit the HTML code for the text field and the status bar to make things clearer. The textarea
element is enclosed by a label
element followed by the desired meter
element. To get from the textarea
element to the meter
element, we use the text field’s labels
property. This is a NodeList array, and we are interested in the first element (with the index 0
), because the following element (the nextSibling
) is the meter
element.
If you look closely, the procedure is not as complicated as it at first looks, but it has a few snags. If there is a stray whitespace or line break that sneaks in between the enclosing label
element and the meter
element, then our status display no longer works. The nextSibling
then becomes a text element, and we can no longer reach the meter
element in the for
loop.
Next we want to program the progress display at the end of the form. You probably guessed that it is a progress
element; More interesting is how we can elegantly express updating this element in JavaScript. First, here is the HTML code for the element:
<label>Progress:
<progress id=formProgress value=0
tabindex=-1></progress></label>
We assign to the progress
element an id
, a starting value of 0
(value
), and a negative tabindex
, which means that the element is never accessed with the Tab key. The JavaScript function updateProgress()
updates the progress element:
function updateProgress() {
var req = document.querySelectorAll(":required");
count = 0;
for(var i=0; i<req.length; i++) {
if (req[i].value != '') {
count++;
}
}
var pb = document.getElementById("formProgress");
pb.max = req.length;
pb.value = count;
}
Because the progress bar is only supposed to refer to the elements that are absolutely required, we pass the character string :required
to the function querySelectorAll()
. The result is a NodeList containing only elements that have the required
attribute. A loop is then run over these elements, checking whether the value
attribute matches a nonempty character string. If this condition applies (in other words, a value has already been entered), the counter variable count
is increased by one value. To finish, the maximum value of the progress
element is set to the number of all required
fields and the value
to the number of the nonempty elements.
Two buttons are available for submitting the form: Save and Submit. We have already discussed the save function in section 3.4.5, Or Perhaps Better to Not Validate? “formnovalidate”; new in this context is the attribute accesskey
:
<p><input accesskey=T type=submit formnovalidate
value="Save [S]" name=save id=save>
<input accesskey=T type=submit name=submit id=submit
value="Submit [T]">
Keyboard shortcuts are not new in HTML5, but they have not been used much so far. One problem with keyboard shortcuts is that they are activated by different key combinations on different platforms, so you never quite know which key you are supposed to press for a particular shortcut. The HTML5 specification has a suggestion to solve this: The value of the accessKeyLabel
should return a character string that corresponds to the correct value on the platform you are using. You could then use this value in the button’s label or in its title
attribute. Unfortunately, at the time of this writing, not a single browser was capable of outputting this character string.
The information we supply in this chapter explains many of the new options provided in HTML5 for forms. Better times are ahead for web developers, because they will no longer need to grapple with JavaScript libraries for common input elements, such as date and time. In particular, the new form functions will be of great help when working with mobile devices where text input is usually much more difficult than on the computer. Form validation in the browser will also contribute significantly to making the code more transparent and therefore more manageable. But do not forget that client-side validation does not make the server application more secure; potential attackers can easily circumvent these checks.
If this chapter has whet your appetite and you want to try out your freshly acquired knowledge of forms on your own website, go right ahead. The syntax of the new elements and attributes is built in such a way that even older browsers will not produce errors. Users of such browsers will not be able to enjoy the full benefit of the new input elements, but text input is always possible.