1. Explicit labeling
If visible text label is present for a form control: use LABEL element and for-id association. This has the most robust support across browser - assistive technology combinations- old and new. Clicking the label text selects the associated radio button / checkbox or places focus within the control. A label can be associated with a single control using this method. The "for" attribute of the LABEL element is assigned the exact same value of the "id" attribute of the related form control. Explicit association is the method of choice when the label is in one table cell and the related control in another.
Make sure that the asterisk for required fields, where one is present, is included within the label tag. Alternatively, one can set the aria-required="true" on the form control like the (INPUT / SELECT element ).
The code block:
<p><label for="usrname">User name: </label> <input type="text" id="usrname" size="10" /></p> <p><label for="pwd">Password</label> <input type="password" id="pwd" size="12" /></p> <p><label for="telnum">Telephone: </label> <input type="text" name="telnum" id="telnum" /></p>
2. Title attribute, aria-label and off-screen label (via CSS)
When no visible label is present, the following methods pass:
- Title attribute
- Aria-label
- Off-screen label
Most browser-screen reader combinations generally used by vision impaired users support all of the above. The aria-label method is fairly well supported at least since 2011. The title is the easiest to implement and has the greatest support even with older browser-AT combinations used by vision impaired individuals. It is displayed visually as a tooltip when one mouses over the form control, so some sighted users can get to it if they need to. But sighted keyboard-only users cannot access the title attribute. This is a serious limitation of the title attribute across all browsers.
The aria-label is equally easy to implement. It is the next best choice after the title attribute. The off-screen label (via CSS) is less preferred lately simply because two workable methods that are much easier to implement are available. It may be noted that users of speech recognition software like Dragon NaturallySpeaking will not be able to rely on any of the above in order to identify the control.
When one of the above methods is used to name a field, make sure the visual cue for required fields(if one is present) is also conveyed via text.
Example: title="Address line 1(*)" or title="Date of birth (required)"
Alternatively, the aria-required attribute may be employed as demonnstrated in later sections.
The code block:
<dl> <dt>Title attribute: </dt> <dd><input type="text" title="Enter search phrase" /></dd> <dt>Aria-label: </dt> <dd><input type="text" aria-label="Enter search phrase" /></dd> <dt>Off-screen label: </dt> <dd><label class="offscreen" for="hideoff">Enter search text: </label> <input type="text" id="hideoff" /> </dl>
3. Form control with two labels
The code block:
<label for="dist">The airport is </label> <input type="text" size="3" id="dist" value="5" /> <label for="dist"> miles away.</label>
Or, the alternative
<label for="left1">The airport is</label> <input id="left1" placeholder="5" aria-describedby="miles" type="text" size="3" /> <span id="miles">miles away.</span></p>
4. Implicit labeling
Implicit association, in which the label tag is wrapped around the form control is now supported by JAWS, NVDA and VoiceOver. This is easier to implement than explicit association. This works well especially when two labels need to be associated with a form control like the statement for miles from airport in the example below. The label can be clicked with a mouse to check the radio button / checkbox or to place focus inside the edit box contained within the label tag. However implicit association cannot be used in some situations like when the label is in one table cell and the form control in another. Also, voice input software like Dragon NaturallySpeaking does not support implicit labels.
The code block:
<p><label>Customer name: <input name="custname" type="text" /></label></p> <p><label>Telephone: <input type="text" name="custtel" /></label></p> <p><label><input type="radio" name="tel" />This is a land line</label></p> <p><label><input type="radio" name="tel" />This is a mobile phone</label></p> <p><label><input type="checkbox" name="txtmsg" />I accept text messages</label> <label>The airport is <input type="text" name="miles1" size="3" value="8" /> miles away.</label>
5. Data table as a container for a form:
This is an example of a table that holds form controls. The column and row heading cells provide the context for individual form controls visually. The aria-labelledby attribute is easy to implement and works reliably with screen readers / screen magnifiers.
But when a table is too wide (many columns) or too long (many rows), it may be difficult for some sighted mouse users to visually relate the corresponding row / column headings for form controls lower down the table. In this situation, the title attribute is better suited.
The code block:
<table border=""> <tr><th></th> <th id="c2">First name</th> <th id="c3">Last name</th> <th id="c4">Social Security Num</th> <th id="c5">Point of contact</th></tr> <tr><th scope="row" id="r1">Applicant #1</th> <td><input type="text" aria-labelledby="r1 c2" /></td> <td><input type="text" aria-labelledby="r1 c3" /></td> <td><input type="text" aria-labelledby="r1 c4" /></td> <td><input type="radio" name="poc" aria-labelledby="r1 c5" /></td> </tr> <tr><th scope="row" id="r2">Applicant #2</th> <td><input type="text" aria-labelledby="r2 c2" /></td> <td><input type="text" aria-labelledby="r2 c3" /></td> <td><input type="text" aria-labelledby="r2 c4" /></td> <td><input type="radio" name="poc" aria-labelledby="r2 c5" /></td> </tr> <tr><th scope="row" id="r3">Applicant #3</th> <td><input type="text" aria-labelledby="r3 c2" /></td> <td><input type="text" aria-labelledby="r3 c3" /></td> <td><input type="text" aria-labelledby="r3 c4" /></td> <td><input type="radio" name="poc" aria-labelledby="r3 c5" /></td> </tr> </table>
6. Multi-part fields like social security# and telephone#:
Here again, the aria-required="true" attribute may be used on individual form controls. Else the asterisk for required fields may be placed within the common label marked up as the legend or group label.
The code block:
Fieldset-Legend Method:
<fieldset> <legend>Social security number: <span style="color: #D90D0D;"> * </span> </legend> <input type="text" size="3" title="First 3 digits" />- <input type="text" size="2" title="Next 2 digits" />- <input type="text" size="4" title="Last 4 digits" /> </fieldset>
Or, Use the role=group method:
<div role="group" aria-labelledby="ssn1"><span id="ssn1">Social Security#</span> <span style="color: #D90D0D;"> * </span> <span> <input size="3" type="text" aria-required="true" title="First 3 digits" />- <input size="2" type="text" aria-required="true" title="Next 2 digits" />- <input size="4" type="text" aria-required="true" title="Last 4 digits" /> </span></div>
7. An alternative for fieldset-legend
The role="group" (or role="radiogroup" for radio buttons) technique is a good tool to have in ones repertoire especially when design constraints make it difficult to use the standard fieldset-legend HTML technique. For instance, when the controls to be grouped are within a table.
The code block:
<table border="" role="presentation"> <tr> <td><label for="amt">Amount to pay $:</label></td> <td><input id="amt" type="text" size="5" /></td> </tr> <tr> <td colspan="2" role="radiogroup" aria-labelledby="ctype"><span id="ctype">Credit Card Type: </span> <span> <input type="radio" id="ct1" name="cc" /> <label for="ct1">Visa </label> | <input type="radio" id="ct2" name="cc" /> <label for="ct2">Mastercard </label> | <input type="radio" id="ct3" name="cc" /> <label for="ct3">American Express </label> | <input type="radio" id="ct4" name="cc" /> <label for="ct4">Discover </label> </span></td> </tr> <tr> <td colspan="2" style="text-align: right;"><input type="submit" value="Next Step" /></td> </tr> </table>
8. Labeling Buttons:
As a general rule, the above push buttons do not need a title attribute to expose the button's name to assistive technology. However it is valid to use a title for the BUTTON element or INPUT (type=image) element to do so. Ensure the title matches the alt-text or value attribute or BUTTON element's content.
The code block:
<dl> <dt>For a BUTTON element: Element's content serves as its label. </dt> <dd><button>Sign in</button> </dd> <dt>Button element with an image as its content that conveys button's purpose: use the alt for the image and an identical title on the button</dt> <dd><button title="Search"><img src="images/search.png" alt="search" /></button></dd> <dt>For INPUT type=button, use the value attribute. This is rendered visually and exposed to assistive technology too.</dt> <dd><input type="button" value="Register" /></dd> <dt>For INPUT type=submit, use the value attribute. This is rendered visually and exposed to assistive technology too.</dt> <dd><input type="submit" value="Apply"/></dd> <dt>For INPUT type=reset, use the value attribute. This is rendered visually and exposed to assistive technology too.</dt> <dd><input type="reset" value="Clear All" /></dd> <dt>For INPUT type="image", use the alt attribute to convey the button's purpose via text</dt> <dd><INPUT type="image" name="Next" src="images/next.gif" alt="Next" title="Next" /></dd> </dl>
9. Case for explicit labeling and aria-labelledby together
Sometimes, the user interface does have a label that is properly associated with the form control and serves most users very well. However, non-sighted users may not find the label text very useful as it might not uniquely identify the control. Consider:
In this scenario, place an aria-labelledby attribute within the form control too which points to a "label" - the h3 text for the specific laptop in this case. The label referenced by aria-labelledby gains precedence when being exposed to assistive technology. Users who wish to click the text that is commonly identified as the label visually (i.e. "Check to compare" in this case) in order to access the form control can still do so.
Notice also that the "Add to cart" buttons are deliberately marked up differently. The alt attribute identifies the button's purpose that clearly includes the product's identity for the first and third laptops. The aria-labelledby attribute is employed to fully convey the purpose of the other two buttons (Mini Laptop and Back to School Laptop) to assistive technology. The aria-labelledby attribute references the h3 text (name of the laptop) and the visible button text i.e. content of the button element for the Mini Laptop , and the value attribute for the other one. Here too, the aria-labelledby takes precedence.
At the present time, only Voice Over with Safari on OSX renders the aria-labelledby for the Add To Cart buttons correctly for the Mini Laptop and Back to School Laptop.
Note:A request has been made to NVAccess.org to support the use of aria-labelledby in this manner for buttons. JAWS 14 exposes the aria-attribute for the Mini Laptop's button but repeats the laptop's name. In case of the Back to School Laptop, JAWS exposes the aria-labelledby correctly only when one uses quick-nav ("B" key) to navigate to the button; else it merely reads the value attribute: Add to Cart. Freedom Scientific too has been notified of this.
The code block:
<form action="#" method="post" id="form9"> <em tabindex="0">Check any two laptops and press the Compare Now button for a side by side comparison of features</em> <p><label for="mycart">Items in cart: </label> <input type="text" readonly name="mycart" id="mycart" value="0" /></p> <h3 id="lap1">Gaming Laptop</h3> <p>Text of laptop features</p> <p><input type="checkbox" name="lbl1" id="lbl1" aria-labelledby="lap1" /><label for="lbl1">Check to compare</label> | <input type="image" name="add1" id="add1" onclick="return add2cart()" src="images/tickets-addtocart.png" alt="Add to cart - Gaming Laptop" /></p> <h3 id="lap2">Mini Laptop</h3> <p>Text of laptop features </p> <p><input type="checkbox" name="lbl2" id="lbl2" aria-labelledby="lap2" /><label for="lbl2">Check to compare</label> | <button name="add2" id="add2" onclick="return add2cart()" aria-label="Add to Cart - Mini Laptop">Add to cart</button> </p> <h3 id="lap3">Fully Featured Touchscreen Laptop</h3> <p>Text of laptop features </p> <p><input type="checkbox" name="lbl3" id="lbl3" aria-labelledby="lap3" /><label for="lbl3">Check to compare</label> | <button name="add3" id="add3" onclick="return add2cart()"><img src="images/tickets-addtocart.png" alt="Add to cart - Fully Featured Touchscreen Laptop" /></button> </p> <h3 id="lap4">Back to School Laptop</h3> <p>Text of laptop features</p> <p><input type="checkbox" name="lbl4" id="lbl4" aria-labelledby="lap4" /><label for="lbl4">Check to compare</label> | <input type="button" name="add4" id="add4" onclick="return add2cart()" value="Add to cart" aria-label="Add to cart - Back to School Laptop" /></p> <table role="presentation"> <tr><td><input type="button" value="Compare Now" id="compare" /></td> <td><input type="button" value="Continue Shopping" id="cshop" /></td> <td><input type="submit" value="Proceed to Checkout" id="chkout" /></td> </tr></table> </form>
10. Caution when using title
In the form below, The customer name field has an identical label and title; the other fields / push buttons have title values that are not the same as the other attributes (e.g. value / alt). The most useful outcome for screen reader users occurs when both the value of the title and the label ttext or button text are exposed:
- Firefox exposes both the label text and the title attribute for edit boxes. JAWS reads both if different in Firefox by default.
- In Internet Explorer, JAWS reads the label by default for edit boxes
- For buttons, JAWS reads both the label and title attribute in forms mode in Firefox and Internet Explorer. When forms mode is off the title is not announced
- NVDA reads the title and label text or button text in Firefox
In conclusion, if the title does not contain supplementary advisory / instructional text, it is problematic to:
- Place different title and value attributes on button element (INPUT type=submit/button), or
- Assign both to a form control: text marked up as a label and a title attribute.
Because in the above situations, the title is exposed as the control's name by some browser-assistive technology combinations creating a mismatch between the control's identity by sighted and vision impaired users. Even when the title attribute contains supplementary advisory or instructional text, the content author runs the risk of this text going unnoticed not only by non-sighted users but even by some sighted users who do not use a mouse.
The code block:
<p><label for="cust4">Customer name: </label> <input type="text" title="Customer name: " id="cust4" /></p> <p><label for="telnum4">Telephone: </label> <input type="text" title="Phone# (only digits and dashes)" id="telnum4" /></p> <input type="submit" title="Proceed to Register" value="Next" /> <button title="For existing users">Sign in</button> <button title="Search now"><img src="images/search.png" alt="search" /></button> <input type="button" value="Register" title="For first time users" />
11. Accessibility violations relating to form labeling
Failure description | Success criterion | WCAG 2 Failure technique |
---|---|---|
Visible label not present | SC 3.3.2 | F82 |
Visible label present but not associated with control (explicit/implicit) | SC 4.2.1 | F68 |
No label association or title / aria-label / labelledby used | SC 4.1.2 | F86 |
Not setting alt attribute for a button (INPUT type=image) | SC 1.1.1 | F65 |
Styling a link as a button but not marking it up as a button | SC 4.1.2 | Not documented |
Not associating common label for a group of controlswhere the common label is necessary to completely convey the purpose of the individual controls | SC 1.3.1 | Not documented |
Instructional text or contextual title of form associated with all controls where that text is not required to determine purpose of individual control | SC 1.3.1 | Not documented |
TheTechniques for WCAG 2.0 acknowledges that not all techniques (and I suppose not all failures) are listted in that document.