A screen reader user tabbing through a form will only hear information programmatically associated with the form field that has focus. When the form field is part of a group, the user needs more context than just the form field label to be able to provide the expected information.
This is particularly true for groups of related checkboxes, radiobuttons and groups of identically labeled form fields. A common example of these are text input fields labeled "address" "city" and "phone number" for "shipping address" and "billing address" when both are presented on the same webpage. The user needs to know whether he is filling in shipping or billing address information (when they are not the same).
Whenever possible, try to use the html construct for grouping form fields, i.e. the fieldset/legend construct.
The fieldset construct has caught some slack because people do not like the default visual presentation.
The presentation can always be modified using CSS, while preserving the programatic relationship that is so important to accessibility.
Also, do keep in mind that visually grouping related form elements is important and helps a lot of people e.g. with cognitive disabilities.
People cannot always use the fieldset/legend construct. There may be many reasons for that, e.g. when your webpage needs to be published tomorrow and changing the html tags will affect the visual appearance and prompt a whole other round of QA testing and meetings.
Scripting and ARIA to the rescue.
How many roads must a man walk down? (not accessible)
To create a group, and associate the common label to that group, we need to do the following:
We took some JQuery and used it to apply the ARIA attributes detailed in the list above. The html code before JQuery is applied is identical between examples 2 and 3, except we had to change the name and ID attributes on the radiobuttons and labels):
How many roads must a man walk down?
Here is the JQuery code that runs on page load and transforms the inaccessible example 2 into the accessible example 3 (requires the JQuery library)
$(document).ready(function () {
$("div#jsinjected p.Question").attr("id", "Question2");
$("div#jsinjected div.answers").attr("role", "group");
$("div#jsinjected div.answers").attr("aria-labelledby", "Question2");
});
If you prefer to use plain old Javascript, you can, it requires a couple of extra lines of code.
The following Javascript function is equivalent to the JQuery solution, should be run onLoad:
function addGroupA11yInfo() {
// select the element that contains all the info.
var x = document.querySelector("div.questionGroup");
// Add a unique ID to the paragraph containing the question.
x.querySelector("p.Question").setAttribute("id", "Question1");
// Selecting the group container element.
var y = x.querySelector("div.answers");
// Mark this container as the group container for the radio buttons and their labels.
y.setAttribute("role", "group");
// Connect the container with the element containing the group label, using the ID we just created.
y.setAttribute("aria-labelledby", "Question1");
}
You can test the difference yourself by comparing the screen reader experience between the examples on this page. Do not use Voiceover (see note #2 below).
Example 1 and 3 should be near identical, since example 1 uses the html construct.
Examples 2 and 3 provide the transition from inaccessible to accessible experience as described below.
Before the change, when you tab to a radiobutton, in the set you will only hear 3 things (the order may vary depending on browser and screen reader used:
You will hear something along the lines of. Radiobutton not checked 22 or 22 radiobutton not checked. You can try it out for yourself using Example 2 on this page.
Notice how you have no idea what the question is? You can find it with a screen reader, but you have to look, which takes time and can be confusing.
After the change, you will hear 4 things (order depends on screen reader/browser combination:
1. Some screen readers announce the common label only when moving focus into and out of the group. It actually provides a good user experience, as users do not need to hear the common label for every choice within the group, as long as they know when they enter and exit the group
2. At this time (November, 2015), the latest versions of Voiceover (on OSX and iOS) do not support either the fieldset/legened construct or the group. We can use the aria-describedby property on the radiobutton that receives focus and point it to the id of the common label question, to create an equivalent experience for the Voiceover user, but ultimately it is on Apple to fix this. Needless to say, Voiceover will not communicate the important accessibility fixes described on this page until this bug has been fixed.
We often come across a label element with a group label associated with a container element for the form fields.
<!-- This is not allowed!! -->This does not work, and is not valid code.
The Definition of the label tag in the html specification states that a label can only be associated with one form control.
If you run the code snippet above through the NU HTML5 Validator you get the following error message for the label associated with div:
Error: The for attribute of the label element must refer to a non-hidden form control.
If this is the case you are dealing with, make sure to remove the "for" attribute from label tag associated with the entire group. Instead you assign it a Unique ID and then associate it with the group container using aria-labelledby as explained above.