The HTML specifications for forms suggests using a
<legend> to define similar items within a form. Normally this is used to combine the forms into large chunks, for instance the billing address, credit card information, and personal information. It’s also useful for combining radio and checkbox sets.
Typically, we associate a form input with a label. The label is announced as the screen reader places focus on the input. This works very well for letting the user know what the checkbox or radio button represents, but it doesn’t give the user context for how it is applied. For instance, the following radio button would be announced as “radio button Yes”. But what is the user saying yes to?
<label for="firstexample"> <input id="firstexample" type="radio" name="test" value="yes" > Yes </label>
Containing the radio buttons within a fieldset and legend gives the radio button context to why you are choosing “yes”.
<fieldset> <legend>Do you like peanut butter on your fish sticks?</legend> <label for="fishyes"> <input id="fishyes" type="radio" name="fish" value="yes" /> Yes </label> <label for="fishno"> <input id="fishno" type="radio" name="fish" value="no" /> No </label> </fieldset>
As you can see, the question can have a big impact on the answer. This is especially true when moving through a form that includes a lot of yes/no questions, such as a tax form.
Using aria-describedby on fieldset-less forms
Sometimes we are not able to rebuild a form from scratch and have to work with a page that uses table layouts or some other set of code that makes it impractical to use the proper HTML coding. The
aria-describedby attribute can help us restore the legend’s semantic value. The aria-describedby attribute has a similar functionality as the title attribute. The information will be announced after a short delay when using Safari and VoiceOver on a Mac. So the user would hear “radio button Yes (pause)… Help tag is Do you like peanut butter on you fish sticks?”. NVDA and JAWS announce the pseudo-legend directly with the radio button’s label.
The h4 has
id="gender". The inputs include
aria-describedby="gender". This simple binding is all that’s needed.
<h4 class="label required" id="gender">Gender:</h4> <input type="radio" id="ad-1" value="2" name="foo" aria-describedby="gender"> <label for="ad-1">Male</label> <input type="radio" id="ad-2" value="1" name="foo" aria-describedby="gender"> <label for="ad-2">Female</label>
While the aria-describedby method connects the radio button with the header, there’s another option that uses the role=”radiogroup” attribute to define the collection as a fieldset and points to the header as the legend.
<h4 class="label required" id="gender2">Gender:</h4> <div role="radiogroup" aria-labelledby="gender2"> <label for="role1"> <input type="radio" id="role1" value="2" name="role">Male </label> <label for="role2"> <input type="radio" id="role2" value="2" name="role">Female </label> </div>
As with ARIA in general, use semantic, valid HTML as the basis for your web applications. This will reduce your div complexity and provide the expected behaviors without compromise. When this is not possible, use the role=”radiogroup” to provide more context to radio buttons and use aria-describedby for grouped form elements.
Visit this test page for more code examples: Using fieldsets and aria-describedby with radio buttons.
Thanks to Jared Smith for suggesting the role=”radiogroup” approach.
— Jared Smith (@jared_w_smith) September 26, 2013