Simon & Matt's new Photoshop book is out now!

Photoshop CS3 Layers Bible book cover

Sharpen your Photoshop skills today!

PageKits.com Featured PageKits

Naturespace PageKit
Naturespace ($54.99)


Fizz (Blue) PageKit
Fizz (Blue) ($24.99)


See more! > >

 

Tutorial: Advanced HTML forms

Level: Advanced. Published on 4 December 2006 in HTML

Learn about some of the advanced features of HTML forms, including fieldsets, legends, labels, option groups, tabbing order, access keys and disabled/read-only controls. Find out how these features can help to make your forms more usable and accessible, and prettier too!

In Building forms we looked at the basics of creating HTML forms: GET vs POST, text fields, checkboxes, radio buttons and so on. In this tutorial we're going to go a step further and delve into some of the more advanced things you can do with forms.

We'll cover the following topics:

  • Using the fieldset and legend elements to group form fields in a logical way
  • Adding labels to form fields with the label element
  • Grouping items in a select menu with option groups
  • Controlling the tabbing order of the elements in a form
  • Speeding up form access and improving accessibility through the use of access keys
  • Setting form elements to be disabled or read-only to clarify their status
  • Styling forms with CSS to make them attractive and easy to use

By the end of this tutorial you'll be well on your way to designing beautiful and accessible Web forms! Read on...

Grouping form fields with fieldsets

In the past you've probably built, or at least seen, complex forms with many, many fields to fill in. (Shopping cart checkouts spring to mind.) If the fields are all bunched together on the page, the effect can be confusing for the visitor, if not downright overwhelming.

The sensible approach is to group fields together so the form makes more sense and is less intimidating. You can of course do this visually with whitespace, colours, or separator bars. However, HTML gives us a way to group fields at a structural level instead - the fieldset element. By grouping fields within fieldsets, you can not only visually group the areas of your form, but structurally group them too. This means that the browser knows which fields are grouped together - great for things such as screen readers, for instance.

Here's a simple example. Let's say we're building the proverbial shopping cart checkout form. We might group the form fields into fieldsets such as billing address, shipping address, and payment details, as follows:


<form action="">
  <fieldset>
    <legend>Billing details</legend>
    <p>Name: <input type="text" name="billingName"/></p>
    <p>Address: <input type="text" name="billingAddress"/></p>
    <p>Postal code: <input type="text" name="billingPostcode"/></p> 
    <p>Country: <select name="billingCountry"><option>Australia</option><option>Canada</option><option>New Zealand</option><option>United Kingdom</option><option>United States</option></select></p>
  </fieldset>
  <fieldset>
    <legend>Shipping details</legend>
    <p>Name: <input type="text" name="shippingName"/></p>
    <p>Address: <input type="text" name="shippingAddress"/></p>
    <p>Postal code: <input type="text" name="shippingPostcode"/></p> 
    <p>Country: <select name="shippingCountry"><option>Australia</option><option>Canada</option><option>New Zealand</option><option>United Kingdom</option><option>United States</option></select></p>
  </fieldset>
  <fieldset>
    <legend>Payment details</legend>
    <p>Card number: <input type="text" name="cardNumber"/></p>
    <p>CVV code: <input type="text" name="cvvCode"/></p>
    <p>Expiry date: <input type="text" name="expiryDate"/></p> 
  </fieldset>
  <div id="buttons">
    <input type="button" name="paymentButton" value="Make payment"/>
  </div>
</form>

Here's what the above form looks like:

Billing details

Name:

Address:

Postal code:

Country:

Shipping details

Name:

Address:

Postal code:

Country:

Payment details

Card number:

CVV code:

Expiry date:

Not the most attractive form admittedly, but you get the idea! (Don't worry, we'll smarten it up later on.)

The <fieldset></fieldset> tags are used to group the fields into fieldsets. After each opening <fieldset> tag, a legend element is used to add a caption to the fieldset. This caption is not only useful as a visual indicator of the type of fields in the fieldset, but it's also very handy for people who are using non-visual browsers such as screen readers.

Improving accessibility with field labels

In the above example, we've simply placed the field labels ("Name:", "Address:" and so on) before our fields in the markup. While this works, it also lacks any structural association between the field labels and the fields themselves. How is the browser supposed to know that "Address:" is the label for the billingAddress field, for example?

Luckily, HTML provides us with a way to structurally link field labels with the fields themselves: the label element. The basic syntax is:


<label for="fieldId">label text</label>
<input id="fieldId" ...

The label is associated with its field using for="fieldId" (so each field in the form needs to be given an ID).

Again, structural markup like this is great for people using screen readers. Rather than the screen reader just saying "Text field" for each field, it can now say "Billing name", for example.

Here's our above example rewritten using labels to link each label with its respective field:


<form action="">
  <fieldset>
    <legend>Billing details</legend>
    <p><label for="billingName">Name:</label> <input type="text" name="billingName" id="billingName"/></p>
    <p><label for="billingAddress">Address:</label> <input type="text" name="billingAddress" id="billingAddress"/></p>
    <p><label for="billingPostcode">Postal code:</label> <input type="text" name="billingPostcode" id="billingPostcode"/></p> 
    <p><label for="billingCountry">Country:</label> <select name="billingCountry" id="billingCountry"><option>Australia</option><option>Canada</option><option>New Zealand</option><option>United Kingdom</option><option>United States</option></select></p>
  </fieldset>
  <fieldset>
    <legend>Shipping details</legend>
    <p><label for="shippingName">Name:</label> <input type="text" name="shippingName" id="shippingName"/></p>
    <p><label for="shippingAddress">Address:</label> <input type="text" name="shippingAddress" id="shippingAddress"/></p>
    <p><label for="shippingPostcode">Postal code:</label> <input type="text" name="shippingPostcode" id="shippingPostcode"/></p> 
    <p><label for="shippingCountry">Country:</label> <select name="shippingCountry" id="shippingCountry"><option>Australia</option><option>Canada</option><option>New Zealand</option><option>United Kingdom</option><option>United States</option></select></p>
  </fieldset>
  <fieldset>
    <legend>Payment details</legend>
    <p><label for="cardNumber">Card number:</label> <input type="text" name="cardNumber" id="cardNumber"/></p>
    <p><label for="cvvCode">CVV code:</label> <input type="text" name="cvvCode" id="cvvCode"/></p>
    <p><label for="expiryDate">Expiry date:</label> <input type="text" name="expiryDate" id="expiryDate"/></p> 
  </fieldset>
  <div id="buttons">
    <input type="button" name="paymentButton" value="Make payment"/>
  </div>
</form>

And here's what it looks like. Notice that on most browsers you can click on the field labels to give focus to the fields themselves. This is particularly useful for those tiny checkbox and radio button fields!

Billing details

Shipping details

Payment details

Enhancing select menus with option groups

Option groups are great when you have a select menu with a lot of options. Just as fieldsets help to group form fields into logical sections, option groups let you classify options within a menu.

Let's say our online store sells 3 types of toys - rattles, teddy bears and balls - and each toy comes in different options. We could have all these variants in the one menu as follows:

It works, but it's a bit hard to read. Let's use option groups to classify the options by the type of toy:


<select name="toy">
  <optgroup label="Rattles">
    <option>Blue rattle</option>
    <option>Green rattle</option>
    <option>Stripy rattle</option>
  </optgroup>
  <optgroup label="Teddy bears">
    <option>Humphrey bear</option>
    <option>Cyril bear</option>
    <option>Janet bear</option>
  </optgroup>
  <optgroup label="Balls">
    <option>Soft ball</option>
    <option>Beach ball</option>
    <option>Spiky ball</option>
  </optgroup>
</select>

And here's how it looks:

That's better! Now we can visually differentiate between the different product types. Much easier to use.

Setting the tabbing order of form fields

As you probably know, with most browsers you can use the Tab key to move between the form controls and links in a page. Many people find this much quicker and easier than clicking on the page elements with their mouse (and of course many people don't even use mice!).

This is great, but sometimes the tabbing order goes awry. The browser determines the tabbing order by the order the elements are placed in the markup, which usually works OK. However, consider the following example with form fields in a table:


<form action="">
  <table style="width: 100%; border: none;">
    <tr>
      <td>Name:<br/><input type="text" name="billingName"/></td>
      <td>Postal code:<br/><input type="text" name="billingPostcode"/></td>
    </tr>
    <tr>
      <td>Address:<br/><input type="text" name="billingAddress"/></td>
      <td>Country:<br/><select name="billingCountry"><option>Australia</option><option>Canada</option><option>New Zealand</option><option>United Kingdom</option><option>United States</option></select></td>
    </tr>
  </table>
</form>

Here's how this form looks:

Name:
Postal code:
Address:
Country:

As a visitor you'd probably expect the tabbing order to be Name, Address, Postal code, then Country. If you try tabbing through the fields though, you'll see that the tabbing order is the order that they appear in the markup: Name, Postal code, Address, Country.

We can fix this with the tabindex attribute, like this:


<form action="">
  <table style="width: 100%; border: none;">
    <tr>
      <td>Name:<br/><input type="text" name="billingName" tabindex="1"/></td>
      <td>Postal code:<br/><input type="text" name="billingPostcode" tabindex="3"/></td>
    </tr>
    <tr>
      <td>Address:<br/><input type="text" name="billingAddress" tabindex="2"/></td>
      <td>Country:<br/><select name="billingCountry" tabindex="4"><option>Australia</option><option>Canada</option><option>New Zealand</option><option>United Kingdom</option><option>United States</option></select></td>
    </tr>
  </table>
</form>

Now the form fields are in the expected tab order - try tabbing through them:

Name:
Postal code:
Address:
Country:

Using access keys for quick keyboard access

To further enhance your forms for people who use the keyboard, you can assign access keys to your form elements. Visitors can then press Alt+accesskey (Windows browsers) / Control+accesskey (Mac browsers) to give focus to, or otherwise manipulate the element. The following HTML elements can have access keys assigned to them:

a (a link)
Generally follows the link when the access key is pressed.
area (an image map "hotspot" link)
Generally follows the link when the access key is pressed.
button (a form button)
Gives focus to the button, or on some browsers, "clicks" the button, when the access key is pressed.
input (a form input control)
For text input types: gives focus to the control when the access key is pressed. For all other input types: pressing the access key usually "clicks" on the control (e.g. checks/unchecks a checkbox or "clicks" a button).
legend (a fieldset legend)
Gives focus to the first form field in the fieldset associated with the legend when the access key is pressed.
object (a generic inclusion of an object, e.g. a Flash movie)
Generally gives focus to the object when the access key is pressed.
select (a drop-down menu)
Generally gives focus to the menu when the access key is pressed.
textarea (a multi-line text input control)
Generally gives focus to the textarea when the access key is pressed.

Be careful when choosing access keys, as they will often prevent browser menu options that use the same keyboard shortcut from working. For example, if you assign an access key of 'F' to a form field, Windows users will no longer be able to select the File menu with Alt+F while viewing your page. You'll need to decide for yourself which is more important: your form field or the menu option!

Indicating access keys

According to the W3C HTML specification, the browser should ideally indicate the access keys to the visitor somehow (e.g. by underlining the access key in the form label). In practice, hardly any browsers do this, so it's up to you to indicate the available access keys to your visitors. You could, for example, underline or bold the appropriate letter in the label text.

An example

Let's enhance our "form in a table" example above with access keys:


<form action="">
  <table style="width: 100%; border: none;">
    <tr>
      <td><span style="text-decoration: underline;">N</span>ame:<br/><input type="text" name="billingName" tabindex="1" accesskey="N"/></td>
      <td><span style="text-decoration: underline;">P</span>ostal code:<br/><input type="text" name="billingPostcode" tabindex="3" accesskey="P"/></td>
    </tr>
    <tr>
      <td><span style="text-decoration: underline;">A</span>ddress:<br/><input type="text" name="billingAddress" tabindex="2" accesskey="A"/></td>
      <td><span style="text-decoration: underline;">C</span>ountry:<br/><select name="billingCountry" tabindex="4" accesskey="C"><option>Australia</option><option>Canada</option><option>New Zealand</option><option>United Kingdom</option><option>United States</option></select></td>
    </tr>
  </table>
</form>

Here's how it looks. Try pressing the access keys (don't forget to use them with the Control or Alt keys as appropriate):

Name:
Postal code:
Address:
Country:

Disabled and read-only controls

You can prevent user interaction with your form controls to various degrees with the disabled and readonly attributes - for example:


<select name="myfield" disabled="disabled" /> ... </select>
<input type="text" name="myfield" value="Hi there!" readonly="readonly" />

Here's a summary of the differences between these two attributes:

disabled
This totally locks the control and prevents the user from interacting with it in any way. The control cannot receive focus. The value of the field is also not sent when the form is submitted.
readonly
Only the value of the field is locked, so the user can't change it. The user can still interact with the control - for example, if it's a checkbox the user can still check/uncheck it (which makes readonly a bit pointless for checkboxes and radio buttons!). The control can also receive focus, and the value of the field is sent when the form is submitted. readonly can only be used on input and textarea controls.

Examples

Try clicking on each of these fields to see what happens (if anything!):

Making it all look pretty

We've now covered how to make your forms more usable and accessible using fieldsets, legends, labels, option groups, tabbing order, access keys and disabled and read-only controls. In this last section we'll show how we can style all these elements using CSS.

Let's take our ugly checkout form that we created at the start. Here's the ugly form with no CSS styling, and here's the same form, styled using CSS.

Take a look at the source of the pretty form - the CSS is in the head element near the top of the page. Let's briefly work through how we styled the form elements.


form
{
  width: 400px;
  color: #3E4A49;
  background-color: #FEF7D6;
  padding: 20px;
  border: 2px solid #4899BE;
  font-family: "Trebuchet MS", Arial, Helvetica, Sans-serif;
  font-size: 0.8em;
}

Here we've set a fixed width on the form to prevent it stretching too wide, and set a nice colour and background colour. The padding gives the form room to "breathe". Finally we've set a pretty blue border around the form, given all the text in the form a nice font, and taken the font size down a bit to make it more visually appealing.


fieldset
{
  padding: 0 20px 20px;
  margin: 0 0 20px;
  border: 1px solid #3E4A49;
}

Now we style each of our fieldset elements with some padding, margin, and a nice solid border to replace the default inset border.


legend
{
  color: #FFFFFF;
  background-color: #4899BE;
  font-family: Arial, Helvetica, Sans-serif;
  font-size: 0.9em;
  font-weight: bold;
  padding: 5px;
  margin-bottom: 0;
  width: 9em;
  border: 1px solid #3E4A49;
}

We give the form legends a nice white-on-blue colour scheme and set a bold, smaller Arial font face for a bit of variety. Some padding stops the legend looking cramped, and we set a zero bottom margin to ensure that the gap between the legend and the first field below is consistent across all browsers. Finally we set a fixed width on the legends so they look nice and consistent, and give them the same border colour as the fieldset.


label
{
  display: block;
  float: left;
  clear: left;
  text-align: right;
  width: 30%;
  padding-top: 0.25em;
  margin: 1em 5px 0 0;
}

Now comes the clever stuff. To make sure that our form labels and fields line up nicely, we set the normally inline label elements to display: block so that we can float them to the left of the fields. We use clear: left to ensure that each label clears the float above it and starts flush with the left margin. Aligning the text right makes all the colons line up nicely. Finally we set a width on the labels (required for floated elements), a small amount of padding (to keep the label text vertically aligned with the field), a top margin to add vertical space between the fields, and a 5-pixel right margin to separate each label from its respective field.


input, select
{
  margin: 1em 0 0 0;
  width: 50%;
  border: 1px solid #FEF7D6;
  padding: 2px;
  background: transparent url("field_bg.gif") no-repeat 0 0;
}

Now we style the form fields themselves. We give them the same top margin as the labels and set them to a fixed width (50% of the form width). We then give them a border with the same colour as the form background (i.e. invisible) and set a background image to give that nice inner shadow style (an effect well known to you if you're a Safari user!). We also add a bit of padding so that our field text doesn't sit on top of the shadow.


input:focus, select:focus
{
  border: 1px solid #4899BE;
}

We use the :focus pseudo-class to give each field a blue border when it receives focus (again, a nice effect that Safari does by default). (Sadly :focus isn't supported by Internet Explorer on Windows. Oh well!)


#buttons
{
  text-align: right;
  margin: -15px 0 -5px 0;
}

input.button
{
  width: auto;
  background: #FFFFFF;
  border: 2px solid #4899BE;
}

Finally we style our buttons div (see below) so the the form control buttons are aligned right, and adjust the top and bottom margins so that the buttons are nicely spaced vertically in the form. Then we style the button itself with a normal (auto) width, a white background and a thick blue border.

Markup changes

We did cheat a bit and make a couple of changes to the form markup that couldn't be made in the CSS:


<legend accesskey="B"><span style="text-decoration: underline;">B</span>illing details</legend>
<legend accesskey="S"><span style="text-decoration: underline;">S</span>hipping details</legend>
<legend accesskey="P"><span style="text-decoration: underline;">P</span>ayment details</legend>

We've added access keys for the "Billing details", "Shipping details" and "Payment details" legends. When you press the access key for a legend, the browser usually gives focus to the first field in the fieldset that the label is attached to ("Name" or "Card number" in our case). Try it and see! We've also underlined the access key letter in each legend.

Here's the end result again.

That's it! We've now covered many advanced form topics, including structural markup, good accessibility practices and styling using CSS. Go forth and make beautiful forms!

For more detail on forms and form elements you might like to refer to the W3C HTML 4.01 specification for forms.

The end

That's the end of this article. We hope you found it useful. If you're still stuck and would like further help, check out our online Help Forums, where you can get assistance from members of Elated and other webmasters.

Also, don't forget the free ELATED Extra Newsletter, where you can get more great Web-building articles and tips sent straight to your inbox!

If you would like to offer us feedback on this or any of our articles, please contact us. Have fun!

Top of Page

Sign up to our newsletter

and get free goodies!