Video examples
iOS Voiceover
Android Talkback
MacOS Voiceover Safari
Code examples
Use semantic HTML
- This semantic HTML contains all accessibility features by default.
- It uses CSS pseudo attributes to create the radio indicator, no Javascript.
Disabled and focusable radio inputs (preferred)
- An input using
aria-disabled="true
will be focusable with the tab key - Use JS to preventDefault()
Required radio inputs
Ensuring all screenreaders indicate radio inputs as being required requires some aria and reinforcement.
- Use
aria-required="true"
to indicate the group is required - Use
aria-invalid="true/false"
to indicate an error state - Add
role="radiogroup"
to the<fieldset>
to make thearia-required
attribute valid - Add “Required” as text to the
<legend>
to ensure compliance across all platforms
Radio button cards
-
Delta (prounounced: dell-tah) is the fourth letter of the NATO alphabet.
-
Echo (prounounced: eck-oh) is the fifth letter of the NATO alphabet.
When you can’t use semantic HTML
This custom button requires extra scripting work for roving tabindex and event listeners.
Specialty use cases
Radio mixed with interactive elements
Avoid this pattern when possible! Radio groups are not supposed to consist of nested interactive elements. Radio button focus order is not what you may expect.
- By default, it is not expected behavior that each radio button can be tabbed to. This is how radio buttons naturally behave
- As soon as a radio button is selected, the selected radio input receives focus first from the group. As a result screen reader users may not discover a nested control for an option if they start switching between radio buttons alone
-
To try to mitigate screen reader users not discovering the nested controls, describe the fieldset / radiogroup with non-visual text. This can be done with
aria-describedby
on thefieldset
. For example, “Edit controls are available which follow each radio button” - Ensure the nested controls also have additional context defined by
aria-describedby
. This will help screen reader users understand their purpose. - Use of the same
name
attribute is important to link the radio buttons as a programmatic group - Keyboard functionality such as arrow up/down/left/right should change the selected radio button.
Developer notes
Name
label
text must describe the radio input.- Use
aria-describedby="hint-id"
for hints or additional descriptions aria-label="Radio input purpose"
can also be used (as a last resort)
Role
- By default, semantic HTML radio inputs identify as radio button
- Use
role="radio"
for custom elements
Group
- Semantic HTML
<fieldset>
must wrap the radio group<legend>
must describe the group’s purpose- Each
<label>
must includefor="input-id"
to be associated with its input
- Custom elements
- Use
role="radiogroup"
to take the place of fieldset - Use
aria-labelledby="label-id"
to associate an element as a label aria-label="Group purpose"
can also be used if there’s no label with an ID
- Use
State
- Semantic HTML
checked
(will be read as “selected” by screen reader)- Use the
disabled
state for inactive buttons
- Custom element
- Use
aria-checked="true/false"
to express state - Use
aria-disabled="true"
to declare inactive elements
- Use
Focus
- Focus must be visible
- Custom elements will require keyboard event listeners and roving tabindex
- DO NOT put interactive elements inbetween radio inputs.
- Performs its purpose across platforms, devices and viewports