You are here: Home Dive Into HTML5


A Form of Madness

 

Diving In

Everybody knows about web forms, right? Make a <form>, a few <input type="text"> elements, maybe an <input type="password">, finish it off with an <input type="submit"> button, and you’re done.

You don’t know the half of it. HTML5 defines over a dozen new input types that you can use in your forms. And when I say “use,” I mean you can use them right now — without any shims, hacks, or workarounds. Now don’t get too excited; I don’t mean to say that all of these exciting new features are actually supported in every browser. Oh goodness no, I don’t mean that at all. In modern browsers, yes, your forms will win at life. But in legacy browsers, your forms will still work, albeit with less winning. Which is to say, all of these features degrade gracefully in every browser. Even IE 6.

Placeholder Text

Placeholder support
IEFirefoxSafariChromeOperaiPhoneAndroid
10.0+4.0+4.0+4.0+11.0+4.0+2.1+

The first improvement HTML5 brings to web forms is the ability to set placeholder text in an input field. Placeholder text is displayed inside the input field as long as the field is empty. When you click on (or tab to) the input field and start typing, the placeholder text disappears.

You’ve probably seen placeholder text before. For example, Mozilla Firefox includes placeholder text in the location bar that reads “Go to a Website”:

location bar with placeholder text

When you click on (or tab to) the location bar, the placeholder text disappears:

location bar with cursor and no placeholder text

Here’s how you can include placeholder text in your own web forms:

<form>
  <input name="q" placeholder="Go to a Website">
  <input type="submit" value="Search">
</form>

Browsers that don’t support the placeholder attribute will simply ignore it. No harm, no foul. See whether your browser supports placeholder text.

Ask Professor Markup

Q: Can I use HTML markup in the placeholder attribute? I want to insert an image, or maybe change the colors.
A: The placeholder attribute can only contain text, not HTML markup. However, there are some vendor-specific CSS extensions that allow you to style the placeholder text in some browsers.

Autofocus Fields

Autofocus support
IEFirefoxSafariChromeOperaiPhoneAndroid
10.0+4.0+4.0+3.0+10.0+·3.0+

angry guy with arms up

Web sites can use JavaScript to focus the first input field of a web form automatically. For example, the home page of Google.com will autofocus the input box so you can type your search keywords. While this is convenient for most people, it can be annoying for power users or people with special needs. If you press the space bar expecting to scroll the page, the page will not scroll because the focus is already in a form input field. (It types a space in the field instead of scrolling.) If you focus a different input field while the page is still loading, the site’s autofocus script may “helpfully” move the focus back to the original input field, disrupting your flow and causing you to type in the wrong place.

Because the autofocusing is done with JavaScript, it can be tricky to handle all of these edge cases, and there is little recourse for people who don’t want a web page to “steal” the focus.

To solve this problem, HTML5 introduces an autofocus attribute on all web form controls. The autofocus attribute does exactly what it says on the tin: as soon as the page loads, it moves the input focus to a particular input field. But because it’s just markup instead of script, the behavior will be consistent across all web sites. Also, browser vendors (or extension authors) can offer users a way to disable the autofocusing behavior.

Here’s how you can set a form field to autofocus:

<form>
  <input name="q" autofocus>
  <input type="submit" value="Search">
</form>

Browsers that don’t support the autofocus attribute will simply ignore it. See whether your browser supports autofocus fields.

What’s that? You say you want your autofocus fields to work in all browsers, not just these fancy-pants HTML5 browsers? You can keep your current autofocus script. Just make two small changes:

  1. Add the autofocus attribute to your HTML markup
  2. Detect whether the browser supports the autofocus attribute, and only run your own autofocus script if the browser doesn’t support autofocus natively.

Autofocus with fallback

<form name="f">
  <input id="q" autofocus>
  <script>
    if (!("autofocus" in document.createElement("input"))) {
      document.getElementById("q").focus();
    }
  </script>
  <input type="submit" value="Go">
</form>
…

See an example of autofocus with fallback.

Setting focus as early as possible

Lots of web pages wait until window.onload fires to set focus. But the window.onload event doesn’t fire until after all your images have loaded. If your page has a lot of images, such a naive script could potentially re-focus the field after the user has started interacting with another part of your page. This is why power users hate autofocus scripts.

The example in the previous section placed the auto-focus script immediately after the form field that it references. This is the optimal solution, but it may offend your sensibilities to put a block of JavaScript code in the middle of your page. (Or, more mundanely, your back-end systems may just not be that flexible.) If you can’t insert a script in the middle of your page, you should set focus during a custom event like jQuery’s $(document).ready() instead of window.onload.

Autofocus with jQuery fallback

<head>
<script src="jquery.min.js"></script>
<script>
  $(document).ready(function() {
    if (!("autofocus" in document.createElement("input"))) {
      $("#q").focus();
    }
  });
</script>
</head>
<body>
<form name="f">
  <input id="q" autofocus>
  <input type="submit" value="Go">
</form>

See an example of autofocus with jQuery fallback.

jQuery fires its custom ready event as soon as the page DOM is available — that is, it waits until the page text is loaded, but it doesn’t wait until all the images are loaded. This is not an optimal approach — if the page is unusually large or the network connection is unusually slow, a user could still start interacting with the page before your focus script executes. But it is still far better than waiting until the window.onload event fires.

If you are willing and able to insert a single script statement in your page markup, there is a middle ground that is less offensive than the first option and more optimal than the second. You can use jQuery’s custom events to define your own event, say autofocus_ready. Then you can trigger this event manually, immediately after the autofocus form field is available. Thanks to E. M. Sternberg for teaching me about this technique.

Autofocus with a custom event fallback

<head>
<script src="jquery.min.js"></script>
<script>
  $(document).bind('autofocus_ready', function() {
    if (!("autofocus" in document.createElement("input"))) {
      $("#q").focus();
    }
  });
</script>
</head>
<body>
<form name="f">
  <input id="q" autofocus>
  <script>$(document).trigger('autofocus_ready');</script>
  <input type="submit" value="Go">
</form>

See an example of autofocus with a custom event fallback.

This is as optimal as the first approach; it will set focus to the form field as soon as technically possible, while the text of the page is still loading. But it transfers the bulk of your application logic (focusing the form field) out of the body of the page and into the head. This example relies on jQuery, but the concept of custom events is not unique to jQuery. Other JavaScript libraries like YUI and Dojo offer similar capabilities.

To sum up:

Email Addresses

For over a decade, web forms comprised just a few kinds of fields. The most common kinds were

Field TypeHTML CodeNotes
checkbox<input type="checkbox">can be toggled on or off
radio button<input type="radio">can be grouped with other inputs
password field<input type="password">echos dots instead of characters as you type
drop-down lists<select><option>…
file picker<input type="file">pops up an “open file” dialog
submit button<input type="submit">
plain text<input type="text">the type attribute can be omitted

All of these input types still work in HTML5. If you’re “upgrading to HTML5” (perhaps by changing your DOCTYPE), you don’t need to make a single change to your web forms. Hooray for backward compatibility!

However, HTML5 defines 13 new field types, and for reasons that will become clear in a moment, there is no reason not to start using them.

The first of these new input types is for email addresses. It looks like this:

<form>
  <input type="email">
  <input type="submit" value="Go">
</form>

I was about to write a sentence that started with “in browsers that don’t support type="email"…” but I stopped myself. Why? Because I’m not sure what it would mean to say that a browser doesn’t support type="email". All browsers “support” type="email". They may not do anything special with it (you’ll see a few examples of special treatment in a moment), but browsers that don’t recognize type="email" will treat it as type="text" and render it as a plain text field.

I can not emphasize how important this is. The web has millions of forms that ask you to enter an email address, and all of them use <input type="text">. You see a text box, you type your email address in the text box, and that’s that. Along comes HTML5, which defines type="email". Do browsers freak out? No. Every single browser on Earth treats an unknown type attribute as type="text" — even IE 6. So you can “upgrade” your web forms to use type="email" right now.

What would it mean to say that a browser DID support type="email"? Well, it can mean any number of things. The HTML5 specification doesn’t mandate any particular user interface for the new input types. Most desktop browsers like Safari, Chrome, Opera, and Firefox simply render it as a text box — exactly like type="text" — so your users will never know the difference (until they try to submit the form).

And then there’s the iPhone.

The iPhone does not have a physical keyboard. All “typing” is done by tapping on an on-screen keyboard that pops up at appropriate times, like when you focus a form field in a web page. Apple did something clever in the iPhone’s web browser. It recognizes several of the new HTML5 input types, and dynamically changes the on-screen keyboard to optimize for that kind of input.

For example, email addresses are text, right? Sure, but they’re a special kind of text. For example, virtually all email addresses contain the @ sign and at least one period (.), but they’re unlikely to contain any spaces. So when you use an iPhone and focus an <input type="email"> element, you get an on-screen keyboard that contains a smaller-than-usual space bar, plus dedicated keys for the @ and . characters.

iPhone rendering input type="email" field
Test type="email" for yourself.

To sum up: there’s no downside to converting all your email address form fields to type="email" immediately. Virtually no one will even notice, except iPhone users, who probably won’t notice either. But the ones who do notice will smile quietly and thank you for making their web experience just a little easier.

Web Addresses

Web addresses — which standards wonks call URLs, except for a few pedants which call them URIs — are another type of specialized text. The syntax of a web address is constrained by the relevant Internet standards. If someone asks you to enter a web address into a form, they’re expecting something like “http://www.google.com/”, not “125 Farwood Road.” Forward slashes are common — even Google’s home page has three of them. Periods are also common, but spaces are forbidden. And every web address has a domain suffix like “.com” or “.org”.

Behold... (drum roll please)... <input type="url">. On the iPhone, it looks like this:

iPhone rendering input type="url" field
Test type="url" for yourself.

The iPhone altered its virtual keyboard, just like it did for email addresses, but now optimized for web addresses instead. The space bar has been completely replaced with three virtual keys: a period, a forward slash, and a “.com” button. (You can long-press the “.com” button to choose other common suffixes like “.org” or “.net”.)

Most modern desktop browsers simply render type="url" like a regular text box, so users won’t even notice until they submit the form. Browsers that don’t support HTML5 will treat type="url" exactly like type="text", so there’s no downside to using it for all your web-address-inputting needs.

Numbers as Spinboxes

Next up: numbers. Asking for a number is trickier than asking for an email address or web address. First of all, numbers are more complicated than you might think. Quick: pick a number. -1? No, I meant a number between 1 and 10. 7½? No no, not a fraction, silly. π? Now you’re just being irrational.

My point is, you don’t often ask for “just a number.” It’s more likely that you’ll ask for a number in a particular range. You may only want certain kinds of numbers within that range — maybe whole numbers but not fractions or decimals, or something more esoteric like numbers divisible by 10. HTML5 has you covered.

Pick a number, (almost) any number

<input type="number"
       min="0"
       max="10"
       step="2"
       value="6">

Let’s take that one attribute at a time. (You can follow along with a live example if you like.)

That’s the markup side of a number field. Keep in mind that all of those attributes are optional. If you have a minimum but no maximum, you can specify a min attribute but no max attribute. The default step value is 1, and you can omit the step attribute unless you need a different step value. If there’s no default value, then the value attribute can be the empty string or even omitted altogether.

But HTML5 doesn’t stop there. For the same low, low price of free, you get these handy JavaScript methods as well:

Having trouble visualizing it? Well, the exact interface of a number control is up to your browser, and different browser vendors have implemented support in different ways. On the iPhone, where input is difficult to begin with, the browser once again optimizes the virtual keyboard for numeric input.

iPhone rendering input type="number" field

In the desktop version of Opera, the same type="number" field is rendered as a “spinbox” control, with little up and down arrows that you can click to change the value.

Opera rendering input type="number" field

Opera respects the min, max, and step attributes, so you’ll always end up with an acceptable numeric value. If you bump up the value to the maximum, the up arrow in the spinbox is greyed out.

Opera rendering input type="number" field at max value

As with all the other input types I’ve discussed in this chapter, browsers that don’t support type="number" will treat it as type="text". The default value will show up in the field (since it’s stored in the value attribute), but the other attributes like min and max will be ignored. You’re free to implement them yourself, or you could reuse a JavaScript framework that has already implemented spinbox controls. Just check for the native HTML5 support first, like this:

if (!Modernizr.inputtypes.number) {
  // no native support for type=number fields
  // maybe try Dojo or some other JavaScript framework
}

Numbers as Sliders

Spinboxes are not the only way to represent numeric input. You’ve probably also seen “slider” controls that look like this:

Chrome rendering of input type="range" field as slider control
Test type="range" for yourself.

You can now have slider controls in your web forms, too. The markup looks eerily similar to spinbox controls:

The spitting image

<input type="range"
       min="0"
       max="10"
       step="2"
       value="6">

All the available attributes are the same as type="number"min, max, step, value — and they mean the same thing. The only difference is the user interface. Instead of a field for typing, browsers are expected to render type="range" as a slider control. Safari, Chrome, Opera, Internet Explorer 10, and the iPhone running iOS 5 all do this. (Sadly, the iPhone running older versions of iOS renders it as a simple text box. It doesn’t even optimize its on-screen keyboard for numeric input.) All other browsers simply treat the field as type="text", so there’s no reason you can’t start using it immediately.

Date Pickers

HTML 4 did not include a date picker control. JavaScript frameworks have picked up the slack (Dojo, jQuery UI, YUI, Closure Library), but of course each of these solutions requires “buying into” the framework on which the date picker is built.

HTML5 finally defines a way to include a native date picker control without having to script it yourself. In fact, it defines six: date, month, week, time, date + time, and date + time - timezone.

So far, support is… sparse.

Date picker support
Input Type IE Firefox Safari Chrome Opera iPhone Other browsers
type="date" · · 5.0+ 20.0+ 9.0+ 5.0+ ·
type="datetime" · · 5.0+ · 9.0+ 5.0+ ·
type="datetime-local" · · 5.0+ · 9.0+ 5.0+ ·
type="month" · · 5.0+ · 9.0+ 5.0+ ·
type="week" · · 5.0+ · 9.0+ 5.0+ ·
type="time" · · 5.0+ 20.0+ 9.0+ 5.0+ ·

This is how Opera renders <input type="date">:

Opera's type="date" picker

If you need a time to go with that date, Opera also supports <input type="datetime">:

Opera's type="datetime" picker

If you only need a month + year (perhaps a credit card expiration date), Opera can render a <input type="month">:

Opera's type="month" picker

Less common, but also available, is the ability to pick a specific week of a year with <input type="week">:

Opera's type="week" picker

Last but not least, you can pick a time with <input type="time">:

Opera's type="time" picker

It’s likely that other browsers will eventually support these input types. But just like type="email" and the other input types, these form fields will be rendered as plain text boxes in browsers that don’t recognize type="date" and the other variants. If you like, you can simply use <input type="date"> and friends, make Opera and iOS users happy, and wait for other browsers to catch up. More realistically, you can use <input type="date">, detect whether the browser has native support for date pickers, and fall back to a scripted solution of your choice (Dojo, jQuery UI, YUI, Closure Library, or some other solution).

Date picker with fallback

<form>
  <input type="date">
</form>
...
<script>
  var i = document.createElement("input");
  i.setAttribute("type", "date");
  if (i.type == "text") {
    // No native date picker support :(
    // Use Dojo/jQueryUI/YUI/Closure to create one,
    // then dynamically replace that <input> element.
  }
</script>

OK, this one is subtle. Well, the idea is simple enough, but the implementations may require some explanation. Here goes…

Search. Not just Google Search or Yahoo Search. (Well, those too.) Think of any search box, on any page, on any site. Amazon has a search box. Newegg has a search box. Most blogs have a search box. How are they marked up? <input type="text">, just like every other text box on the web. Let’s fix that.

<form>
  <input name="q" type="search">
  <input type="submit" value="Find">
</form>

New-age search box

Test <input type="search"> in your own browser. In some browsers, you won’t notice any difference from a regular text box. But if you’re using Safari on Mac OS X, it will look like this:

Safari/Mac rendering input type="search" field

Can you spot the difference? The input box has rounded corners! I know, I know, you can hardly contain your excitement. But wait, there’s more! When you actually start typing into the type="search" box, Safari inserts a small “x” button on the right side of the box. Clicking the “x” clears the contents of the field. (Google Chrome, which shares much technology with Safari under the hood, also exhibits this behavior.) Both of these small tweaks are done to match the look and feel of native search boxes in iTunes and other Mac OS X client applications.

Typing in a type="search" field in Safari

Apple.com once used <input type="search"> for their site-search box, to help give their site a “Mac-like” feel. But there’s nothing Mac-specific about it. It’s just markup, so each browser on each platform can choose to render it according to platform-specific conventions. As with all the other new input types, browsers that don’t recognize type="search" will treat it like type="text", so there is absolutely no reason not to start using type="search" for all your search boxes today.

Professor Markup Says

By default, older versions of Safari will not apply even the most basic CSS styles to <input type="search"> fields. If you want to force Safari to treat your search field like a normal text field (so you can apply your own CSS styles), add this rule to your stylesheet:

input[type="search"] {
  -webkit-appearance: textfield;
}

Thanks to John Lein for teaching me this trick.

Color Pickers

HTML5 also defines <input type="color">, which lets you pick a color and returns the color’s hexadecimal representation. No browser supports it yet, which is a shame, because I’ve always loved the Mac OS color picker. Maybe someday. Good news, everyone! Opera 11 now supports type=color. On Mac and Windows, it integrates with the platform's native color picker. On Linux, it drops down a basic color picker. On all platforms, the return value of the input control is a six-digit hexadecimal RGB color, suitable for framing or using anywhere that accepts a CSS color.

Opera rendering of input type="range" field on multiple platforms
Test type="color" for yourself.

Thanks to Patrick Lauke and Chris Mills for relicensing this image for inclusion in this book. You should read their article about the new form features in Opera 11.

Form Validation

Form validation support
IEFirefoxSafariChromeOperaiPhoneAndroid
10.0+4.0+5.0+10.0+9.0+··

In this chapter, I’ve talked about new input types and new features like auto-focus form fields, but I haven’t mentioned what is perhaps the most exciting part of HTML5 forms: automatic input validation. Consider the common problem of entering an email address into a web form. You probably have some client-side validation in JavaScript, followed by server-side validation in PHP or Python or some other server-side scripting language. HTML5 can never replace your server-side validation, but it might someday replace your client-side validation.

There are two big problems with validating email addresses in JavaScript:

  1. A surprising number of your visitors (probably around 10%) won’t have JavaScript enabled
  2. You’ll get it wrong

Seriously, you’ll get it wrong. Determining whether a random string of characters is a valid email address is unbelievably complicated. The harder you look, the more complicated it gets. Did I mention it’s really, really complicated? Wouldn’t it be easier to offload the entire headache to your browser?

Most modern browsers validate type=“email”

error message on invalid type="email" field

That screenshot is from Opera 11, although the functionality has been present since Opera 9. Firefox 4 and Chrome 10 provide similar functionality. The only markup involved is setting the type attribute to "email". When the user tries to submit a form with an <input type="email"> field, the browser automatically offers RFC-compliant email validation, even if scripting is disabled.

HTML5 also offers validation of web addresses entered into <input type="url"> fields, and numbers in <input type="number"> fields. The validation of numbers even takes into account the min and max attributes, so browsers will not let you submit the form if you enter a number that is too large.

error message on invalid type="number" field

There is no markup required to activate HTML5 form validation; it is on by default. To turn it off, use the novalidate attribute.

Don’t validate me, bro

<form novalidate>
  <input type="email" id="addr">
  <input type="submit" value="Subscribe">
</form>

Required Fields

<input required> support
IEFirefoxSafariChromeOperaiPhoneAndroid
10.0+4.0+·10.0+9.0+··

HTML5 form validation isn’t limited to the type of each field. You can also specify that certain fields are required. Required fields must have a value before you can submit the form.

The markup for required fields is as simple as can be:

<form>
  <input id="q" required>
  <input type="submit" value="Search">
</form>

Test <input required> in your own browser. Browsers may supply additional information to required fields. For example, when hovering over a required field a popup appears in Mozilla Firefox:

a popup appears on a required field in Firefox

Furthermore, if you attempt to submit the form without filling in the required value, Firefox will pop up an infobar telling you that the field is mandatory and can not be left blank.

Further Reading

Specifications and standards:

JavaScript libraries:

Useful articles:

This has been “A Form of Madness.” The full table of contents has more if you’d like to keep reading.

Did You Know?

In association with Google Press, O’Reilly is distributing this book in a variety of formats, including paper, ePub, Mobi, and DRM-free PDF. The paid edition is called “HTML5: Up & Running,” and it is available now. This chapter is included in the paid edition.

If you liked this chapter and want to show your appreciation, you can buy “HTML5: Up & Running” with this affiliate link or buy an electronic edition directly from O’Reilly. You’ll get a book, and I’ll get a buck. I do not currently accept direct donations.

Copyright MMIX–MMXI Mark Pilgrim