Forms

Having covered how to create custom controls, we’ll now turn to forms, which are another common problem area ARIA helps address. To repeat myself for a moment, though, the first best practice when creating forms is to always use the native form elements that HTML5 provides. See the last section again for why rolling your own is not a good idea.

When it comes to implementing forms, the logical ordering of elements is one key to simplifying access and comprehension. The use of tabindex can help to correct navigation, as we just covered, but it’s better to ensure your form is logically navigable in the first place. Group form fields and their labels together when you can, or place them immediately next to each other so that one always follows the other in the reading order.

And always clearly identify the purpose of form fields using the label element. You should also always add the new HTML5 for attribute so that the labels can be located regardless of how the reader enters the field or where they are located in the document markup. This attribute identifies the id of the form element the label element labels:

<label id="fname-label" for="fname">First name:</label>

<input type="text"
          id="fname"
          name="first-name"
          aria-labelledby="fname-label" />

I’ve also added the aria-labelledby attribute to the input element in this example to ensure maximum compatibility across systems, but its use is critical if your form field is not identified by a label element (only label takes the for attribute). As the label element can be used in just about every element that can carry a label, there’s little good reason to omit using it.

For example, if you have to use a table to lay out your form, don’t be lazy and use table cells alone to convey meaning:

<table>
    <tr>
        <td>
            <label id="fname-label" for="fname">First name:</label>
        </td>
        <td>
            <input type="text"
                      id="fname"
                      name="first-name"
                      aria-labelledby="fname-label" />
        </td>
    </tr>
    …
<table>

Note that you also should include the for attribute regardless of whether the label precedes, follows or includes the form field.

Another pain point comes when a reader fills in a form only to discover after the fact that you had special instructions they were supposed to follow. When specifying entry requirements for completing the field, include them within the label or attach an aria-describedby attribute so that the reader can be informed right away:

<label for="username-label">User name:</label>

<input type="text"
          id="uname"
          name="username"
          aria-labelledby="username-label"
          aria-describedby="username-req" />

<span id="username-req">User names must be between 8 and 16 characters in length and contain only alphanumeric characters.</span>