Making forms accessible is a simple process. Each form element should be associated with its instructions and errors, and everything should be accessible via the keyboard.
Testing
- Identify each form element.
- Find all instructions associated with each element.
- If a form element isn’t programatically associated with ALL instructions, this is a failure.
- Ensure all field elements are accessible via the keyboard.
- If the form cannot be filled out with just a keyboard, this is a failure.
- Check for title tags
- Title tags can be a substitute for labels.
- If the title tag provides all the related information it passes, if it provides extra information it fails.
- Title tags are not accessible via keyboard.
Examples
Passes
<fieldset>
<legend>Name</legend>
<label for="firstname">First </label>
<input type='text' id='firstname'><br>
<label for="lastname">Last </label>
<input type='text' id='lastname'>
</fieldset>
<fieldset>
<legend>Favorite Soup?</legend>
<input type='radio' name='soup' value='pea' id='pea' title='Pea Soup'> Pea Soup<br>
<input type='radio' name='soup' value='chicken' id='chicken' title='Chicken Noodle'> Chicken Noodle<br>
<input type='radio' name='soup' value='tomato' id='tomato' title='Tomato'> Tomato
</fieldset>
Name: Each form element has a
label
, and its associated with thefor
tag. Thefor
tag refers to theid
of theinput
. When looking at this form, ‘First’ and ‘Last’ wouldn’t make since without ‘Name.’ This is associated with thefieldset
andlegend
. All elements are wrapped in afieldset
. There can only be onelegend
tag perfieldset
. Anything in thelegend
tag will be associated.
Favorite Soup:
Fieldset
andlegend
is often used for radio buttons as its the easiest way to associate the radio buttons with the question. Notice there are nolabel
s for the radio buttons, but each button has atitle
tag for assistive technology to read.
Fails
<fieldset>
<legend>Name</legend>
<label for="first_name-2">First </label>
<input type='text' id='firstname-2'><br>
<label for="1lastname">Last </label>
<input type='text' id='1lastname'>
</fieldset>
<fieldset>
<legend>Favorite Soup?</legend>
<p><span style='color:red;'>This Question Is Required</span></p>
<input type='radio' name='soup' value='pea' id='peasoup' title='Chick Pea Soup'> Pea Soup<br>
<input type='radio' name='soup' value='chicken' id='chicken' title='Chicken Noodle'> Chicken Noodle<br>
<input type='radio' name='soup' value='tomato' id='tomato' title='Tomato'> Tomato
</fieldset>
<br>
Failure: First name label
for
andid
don’t match.
Failure: Last name has an invalid
id
.
Failure: “This Question Is Required” is not associated with the form fields.
Failure: The
title
tag for Pea Soup indicates it’s ‘Chick Pea Soup.’ This information is not available to keyboard, sighted users.
How ARIA afects form inputs
Screen readers vary on what they read and the additional information they provide by default. This is a broad summary of what is read based on VoiceOver for Mac OSX.
You can test these with your own screen reader. If you have a OSX you can turn voice over on by hitting command+f5.
TL;DR Using aria-label
or aria-labelledby
will cause a screen reader to only read them and not the default label. If you want an input to read from multiple things like an error message, use aria-labelledby
and pass it the for
attribute of the label and any aditional id
s you want read. ex. aria-labelledby='car1 car_description car-error-message'
No ARIA
Reads just the label
and not the description
Please enter Make and Model
<label for="car_1">Car</label>
<input type="text" id="car_1"/><br/>
<span id="carmakedescription_1"><i>Please enter Make and Model</i></span>
Screen Reader reads input as: Car Edit text
With aria-label
Reads the aria-label
and doesn’t read the normal label
.
Please enter Make and Model
<label for="car_2">Car</label>
<input type="text" id="car_2" aria-label="Car, please enter make and model" /><br/>
<span id="carmakedescription_2"><i>Please enter Make and Model</i></span>
Screen Reader reads input as: Car, please enter make and model Edit text
With aria-labelledby pointing at carmakedescription
Reads only the aria-labelledby
attribute and not the default label
Please enter Make and Model
<label for="car_3">Car</label>
<input type="text" id="car_3" aria-labelledby="carmakedescription_3" /><br/>
<span id='carmakedescription_3'><i>Please enter Make and Model</i></span>
Screen Reader reads input as: Please enter Make and Model Edit text
With aria-labelledby pointing at car carmakedescription
Reads both labels indicated by the aria-labelledby
attribute
Please enter Make and Model
<label for="car_4">Car</label>
<input type="text" id="car_4" aria-labelledby="car_4 carmakedescription_4" /><br/>
<span id='carmakedescription_4'><i>Please enter Make and Model</i></span>
Screen Reader reads input as: Car Please enter Make and Model Edit text
With aria-describedby pointing at carmakedescription
Voiceover only reads the label, Jaws should read the description as well
Please enter Make and Model
<label for="car_5">Car</label>
<input type="text" id="car_5" aria-describedby="carmakedescription_5" /><br/>
<span id='carmakedescription_5'><i>Please enter Make and Model</i></span>
Screen Reader reads input as: Car Edit text