Example in Action: How to Structure a Web Form

The <label> element

As we saw in the previous article, The <label> element is the formal way to define a label for an HTML form widget. This is the most important element if you want to build accessible forms - when implemented properly, screen readers will speak a form element's label along with any related instructions, as well as it being useful for sighted users. Take this example, which we saw in the previous article:

<label for="name">Name:</label> <input type="text" id="name" name="user_name" />

With the <label> associated correctly with the <input> via its for attribute (which contains the <input> element's id attribute), a screen reader will read out something like "Name, edit text".

There is another way to associate a form control with a label - nest the form control within the <label>, implicitly associating it.

<label for="name">
  Name: <input type="text" id="name" name="user_name" />
</label>

Even in such cases however, it is considered best practice to set the for attribute to ensure all assistive technologies understand the relationship between label and widget.

If there is no label, or if the form control is neither implicitly nor explicitly associated with a label, a screen reader will read out something like "Edit text blank", which isn't very helpful at all.


Labels are clickable, too!

Another advantage of properly set up labels is that you can click or tap the label to activate the corresponding widget. This is useful for controls like text inputs, where you can click the label as well as the input to focus it, but it is especially useful for radio buttons and checkboxes - the hit area of such a control can be very small, so it is useful to make it as easy to activate as possible.

For example, clicking on the "I like cherry" label text in the example below will toggle the selected state of the taste_cherry checkbox:

<form>
  <p>
    <input type="checkbox" id="taste_1" name="taste_cherry" value="cherry" />
    <label for="taste_1">I like cherry</label>
  </p>
  <p>
    <input type="checkbox" id="taste_2" name="taste_banana" value="banana" />
    <label for="taste_2">I like banana</label>
  </p>
</form>


Multiple labels

Strictly speaking, you can put multiple labels on a single widget, but this is not a good idea as some assistive technologies can have trouble handling them. In the case of multiple labels, you should nest a widget and its labels inside a single <label> element.

Let's consider this example:

<p>Required fields are followed by <span aria-label="required">*</span>.</p>

<!-- So this: -->
<!--div>
  <label for="username">Name:</label>
  <input id="username" type="text" name="username" required>
  <label for="username"><span aria-label="required">*</label>
</div-->

<!-- would be better done like this: -->
<!--div>
  <label for="username">
    <span>Name:</span>
    <input id="username" type="text" name="username" required>
    <span aria-label="required">*</span>
  </label>
</div-->

<!-- But this is probably best: -->
<div>
  <label for="username">Name: <span aria-label="required">*</span></label>
  <input id="username" type="text" name="username" required />
</div>


The paragraph at the top states a rule for required elements. The rule must be included before it is used so that sighted users and users of assistive technologies such as screen readers can learn what it means before they encounter a required element. While this helps inform users what an asterisk means, it can not be relied upon. A screen reader will speak an asterisk as "star" when encountered. When hovered by a sighted mouse user, "required" should appear, which is achieved by use of the title attribute. Titles being read aloud depends on the screen reader's settings, so it is more reliable to also include the aria-label attribute, which is always read by screen readers.

The above variants increase in effectiveness as you go through them:

  • In the first example, the label is not read out at all with the input - you just get "edit text blank", plus the actual labels are read out separately. The multiple <label> elements confuse the screen reader.
  • In the second example, things are a bit clearer - the label read out along with the input is "name star name edit text required", and the labels are still read out separately. Things are still a bit confusing, but it's a bit better this time because the <input> has a label associated with it.
  • The third example is best - the actual label is read out all together, and the label read out with the input is "name required edit text".

Note: You might get slightly different results, depending on your screen reader. This was tested in VoiceOver (and NVDA behaves similarly). We'd love to hear about your experiences too.