Radio Group

A radio group is a group of radio buttons that allows the user to select one option from a list of options. No more than one radio button in the group may be checked at a time.

A radio group may be implemented using semantic HTML radio buttons within a <fieldset> element (recommended) or using non-semantic HTML elements where the radio group container has a role of radiogroup and the radio buttons have a role of radio.

Role

A group of radio buttons must be enclosed within a container element. The container element must have a role of radiogroup unless semantic HTML radio buttons are used.

Accessibility label

The container element must have an accessible label. If using a <fieldset> element, the <legend> element will be used. When using non-semantic HTML elements, an accessible label should be provided using the aria-labelledby attribute that points to an element that contains the visible label text. If there is not visible label then the aria-label attribute should be used.

Radio group has radios

A radio group container must contain descendants with a role of radio or semantic HTML radio buttons.

Forbidden interactive children

Aside from radio buttons, a radio group must not contain any interactive children such as links or buttons. Such children would be inaccessible to screen reader users since they will be excluded from the accessibility tree.

Radios accessibility labels

Each radio button in the group must have an accessible name. Semantic HTML radio buttons may use an associated <label> element - the radio button input may either be nested within the <label> element or the for attribute may be used to associate the <label> with the radio button input. When using non-semantic HTML elements, a visible text node contained within the element with role radio may serve as the accessible name otherwise the either the aria-label attribute or aria-labelledby attribute may be used to provide an accessible name.

1<!-- A radio group using semantic HTML radio buttons -->
2<fieldset>
3 <legend>Radio Group</legend>
4 <label><input type="radio" name="radio-group" id="radio1" value="radio1" checked />Radio 1</label>
5 <label><input type="radio" name="radio-group" id="radio2" value="radio2" />Radio 2</label>
6 <label><input type="radio" name="radio-group" id="radio3" value="radio3" />Radio 3</label>
7</fieldset>
8
9<!-- A radio group using non-semantic HTML elements -->
10<div role="radiogroup" aria-labelledby="radiogroup-label">
11 <span id="radiogroup-label">Radio Group</span>
12 <div role="radio" id="radio1" aria-checked="true" tabindex="0">Radio 1</div>
13 <div role="radio" id="radio2" aria-checked="false" tabindex="-1">Radio 2</div>
14 <div role="radio" id="radio3" aria-checked="false" tabindex="-1">Radio 3</div>
15</div>

Set size

Optionally, the aria-setsize attribute may be used to indicate the number of radio buttons in the group. If the aria-setsize attribute is used, then it should be set to the number of radio buttons in the group. The aria-setsize attribute must be set on the radio buttons themselves, not the container and it should be consistent across all radio buttons in the group.

Set position

Optionally, the aria-posinset attribute may be used to indicate the position of a radio button in the group. If the aria-posinset attribute is used, then it should be set to the position of the radio button in the group.

ARIA owns

Optionally, the aria-owns attribute may be used to indicate that the radio group owns the radio buttons. This is useful when the radio buttons are not descendants of the radio group container. The aria-owns attribute should be set on the radio group container and should point to the IDs of the radio buttons. Any elements referenced by the aria-owns attribute should have a role of radio.

1<div role="radiogroup" aria-labelledby="radiogroup-label" aria-owns="radio1 radio2 radio3">
2 <span id="radiogroup-label">Radio Group</span>
3</div>
4<div role="radio" id="radio1" aria-checked="true" tabindex="0">Radio 1</div>
5<div role="radio" id="radio2" aria-checked="false" tabindex="-1">Radio 2</div>
6<div role="radio" id="radio3" aria-checked="false" tabindex="-1">Radio 3</div>

Checked radios

At any time, only one radio button in the group may be checked. On initialization it is also permissible for no radio buttons to be checked.

Semantic HTML radio buttons will automatically set the checked attribute on the radio button that is checked. In non-semantic HTML radio buttons, if a radio button is checked, the aria-checked attribute must be set to true. Unchecked radio buttons should have the aria-checked attribute set to false. Checked radio buttons must be in the focus sequence, see Focus management.

Unreachable group

In semantic HTML radio buttons, if a radio button is disabled, the disabled attribute must be set on the radio button input. However, it is not acceptable to have a checked radio button that is disabled or not reacheable by keyboard navigation. This would make the entire radio group unreachable by keyboard since the checked radio button must receive focus when the radio group receives focus.

1<input type="radio" name="radio-group" id="radio1" value="radio1" checked />
2<!-- not reachable by keyboard due to being disabled -->
3<input type="radio" name="radio-group" id="radio1" value="radio1" checked disabled />
4<!-- not reachable by keyboard due to being excluded from the tab index -->
5<input type="radio" name="radio-group" id="radio1" value="radio1" checked tabindex="-1" />

Focus management

When focusing into a radio group where one of the radio buttons is checked, focus should be placed on the checked radio button. If none of the radio buttons are checked, focus should be placed on the first radio button in the group. Once focus is in the group, the next Tab key press should move focus to the next focusable element after the radio group. If the Shift key is held while pressing Tab, focus should move to the previous focusable element before the radio group. In radio groups implemented using native HTML radio buttons, if focus is moved into the radio group by pressing Shift + Tab and no radio button is checked, it is acceptable for focus to be placed on the last radio button in the group.

For radio groups implemented using semantic HTML radio buttons, the browser will handle focus management. For radio groups implemented using non-semantic HTML elements, there are two options for focus management:

  • Make the checked radio button (or first button if no radio is checked) focusable by adding the tabindex="0" attribute. Although not strictly required, it is a best practice to explictly make the unchecked radio buttons unfocusable by adding the tabindex="-1" attribute.
1<div role="radiogroup" aria-labelledby="radiogroup-label">
2 <span id="radiogroup-label">Radio Group</span>
3 <div role="radio" aria-checked="true" tabindex="0">Radio 1</div>
4 <div role="radio" aria-checked="false" tabindex="-1">Radio 2</div>
5 <div role="radio" aria-checked="false" tabindex="-1">Radio 3</div>
6</div>
  • Make the radio group container element focusable by adding the tabindex="0" attribute. Use the aria-activedescedant attribute on the container with the ID of the checked radio button (or first button if no radio is checked). This will cause the browser to move focus to the checked radio button when the radio group container is focused.
1<div role="radiogroup" aria-labelledby="radiogroup-label" tabindex="0" aria-activedescendant="radio1">
2 <span id="radiogroup-label">Radio Group</span>
3 <div role="radio" id="radio1" aria-checked="true">Radio 1</div>
4 <div role="radio" id="radio2" aria-checked="false">Radio 2</div>
5 <div role="radio" id="radio3" aria-checked="false">Radio 3</div>
6</div>

Keyboard navigation

Once focus is in the radio group, the Arrow keys may be used to move selection and focus between radio buttons in the group.

  • The ArrowDown and ArrowRight keys should move focus and change the selection to the next radio button in the group. If focus is on the last radio button in the group, it should loop around to the first radio button.
  • The ArrowUp and ArrowLeft keys should move focus and change the selection to the previous radio button. If focus is on the first radio button in the group, it should loop around to the last radio button.

For radio groups implemented using semantic HTML radio buttons, the browser will handle keyboard navigation. For radio groups implemented using non-semantic HTML elements, the Arrow keys may be handled using JavaScript.

1const radios = document.querySelectorAll('[role="radio"]');
2const radioGroup = document.querySelector('[role="radiogroup"]');
3let index = 0;
4
5// using tabindex
6function handleKeyUp(event) {
7 const { key } = event;
8 if (key === 'ArrowDown' || key === 'ArrowRight') {
9 index = index === radios.length - 1 ? 0 : index + 1;
10 } else if (key === 'ArrowUp' || key === 'ArrowLeft') {
11 index = index === 0 ? radios.length - 1 : index - 1;
12 } else {
13 return;
14 }
15 for (let i = 0; i < radios.length; i++) {
16 // update tabindex and aria-checked attributes
17 radios[i].setAttribute('tabindex', i === index ? '0' : '-1');
18 radios[i].setAttribute('aria-checked', i === index);
19 }
20 // focus the selected radio button
21 radios[index].focus();
22}
23
24// using aria-activedescendant
25function handleKeyUp(event) {
26 const { key } = event;
27 if (key === 'ArrowDown' || key === 'ArrowRight') {
28 index = index === radios.length - 1 ? 0 : index + 1;
29 } else if (key === 'ArrowUp' || key === 'ArrowLeft') {
30 index = index === 0 ? radios.length - 1 : index - 1;
31 } else {
32 return;
33 }
34 for (let i = 0; i < radios.length; i++) {
35 // update aria-checked attribute
36 radios[i].setAttribute('aria-checked', i === index);
37 }
38 // focus the selected radio button and update aria-activedescendant attribute
39 radios[index].focus();
40 radioGroup.setAttribute('aria-activedescendant', radios[index].id);
41}
42
43radioGroup.addEventListener('keyup', handleKeyUp);

Toolbar radio groups

Radio groups are often used in toolbars. In this case there are some important differences in keyboard navigation:

  • The Arrow keys should not change the selection, they should only move focus between radio buttons in the group.
  • The Space key should change the selection to the focused radio button if it is unchecked.
  • Optionally the Enter key may also change the selection to the focused radio button if it is unchecked.
  • When focus is on the last radio button in the group, the ArrowRight key should move the focus to the next element in the toolbar rather than looping around to the first radio button in the group.
  • When focus is on the first radio button in the group, the ArrowLeft key should move the focus to the previous element in the toolbar rather than looping around to the last radio button in the group.
  • Navigation using the ArrowDown and ArrowUp keys is optional. If implemented, the ArrowDown key should move focus to the next element and the ArrowUp key should move focus to the previous element.

Summary of Tests

NameConformance LevelWCAG Success Criteria
RoleA4.1.2 Name, Role, Value
Accessibility labelA4.1.2 Name, Role, Value
Radio group has radiosA4.1.2 Name, Role, Value, 1.3.1 Info and Relationships
Forbidden interactive childrenA4.1.2 Name, Role, Value
Radios accessibility labelsA4.1.2 Name, Role, Value
Set sizeA1.3.1 Info and Relationships
Set positionA1.3.1 Info and Relationships
ARIA ownsA1.3.1 Info and Relationships
Checked radiosA4.1.2 Name, Role, Value
Unreachable radiosA2.1.1 Keyboard
Focus managementA2.1.1 Keyboard, 2.4.3 Focus Order
Keyboard navigationA2.1.1 Keyboard