Search topics
Radio buttons and checkboxes without a group name
A checkout asks its questions in bold text above each set of options, but nothing ties the question to the options, so a screen reader reads “Yes, radio button” with no question.
The problem
Screen reader users hear “Yes” or “Express” but not the question it answers.
An online shop's checkout asks two questions before payment. "Delivery speed" offers Standard and Express as radio buttons. "Leave the parcel if no one is home?" offers Yes and No. Below them, "Send me updates by" offers Email and Text message as checkboxes. Each question is printed in bold above its options, and a sighted user reads the question and then picks an answer. A screen reader user who presses Tab hears "Standard, radio button, checked, 1 of 2", then later "Yes, radio button, not checked, 1 of 2", then "Email, checkbox, not checked". The answers arrive without the questions. Yes to what? Updates about what? The words are on screen, a line above, but nothing in the markup says they belong to the options.
Each question is a p element with a class that makes it bold. The options are real radio buttons and checkboxes with real labels, so each one has a name, but nothing groups them or connects them to the question. 1.3.1 needs the relationships people see to be in the code as well: here, that these options answer this question. A label names one field; it cannot name a set of them. That is the job of a group with its own name, which a screen reader announces as focus enters the group.
The problem grows with the form. One question with "Yes" and "No" is easy to guess from context; a long application form with several yes-or-no questions is not, and someone who comes back to change an answer lands in the middle of a group, well away from its question.
2 of 10 groups affected
- No vision (affected)
- Low vision (not affected)
- Colour vision (not affected)
- No hearing (not affected)
- Hard of hearing (not affected)
- No speech (not affected)
- Motor (not affected)
- Reach, strength (not affected)
- Cognitive (affected)
- Seizures (not affected)
- Without vision Screen reader and braille users reach an option such as “Yes” or “Email” with no question attached, and two groups that both offer “Yes” sound the same.
- Limited language, cognitive and learning abilities People who use a screen reader to support reading, or who move back and forth through a long form, lose the question as soon as they leave the line it is printed on.
Scanners check that every radio button and checkbox has a name, and here they all do, so the form passes. Whether loose text above a set of options is really their question is a judgement about meaning, so most tools don't flag it. ANDI's legend-alone checks the opposite mistake: a legend with no label on each field. A quick AI fix often adds aria-label="Leave the parcel if no one is home? Yes" to each radio button: the question is then read, but it is now hidden text that can drift from the printed words, and voice control users who say "click Yes" may no longer match it. Hearing whether each group's question comes through is something a person has to check.
Try it
Press Tab to move into each question, and use the arrow keys between Yes and No.
Both versions look the same. Below the form, check whether the screen reader hears the question or only the answer.
Broken Can you fix this?
Leave the parcel if no one is home?
Send me updates by
Screen reader hears (Tab into a question)
A recreated demo. The broken version is intentionally inaccessible.
The fix
Make the question the group's name: a fieldset and legend, or a group role pointing at the question.
- 1Every set of radio buttons, and every set of checkboxes answering one question, is grouped in the markup.
- 2The group is named by the question as printed, through a legend or aria-labelledby.
- 3Every option keeps its own label as well as the group name.
<p class="question">Leave the parcel if no one is home?</p><div class="options"> <input id="leave-yes" type="radio" name="leave" value="yes"> <label for="leave-yes">Yes</label> <input id="leave-no" type="radio" name="leave" value="no"> <label for="leave-no">No</label></div> <p class="question">Send me updates by</p><div class="options"> <input id="by-email" type="checkbox" name="updates" value="email"> <label for="by-email">Email</label> <input id="by-text" type="checkbox" name="updates" value="text"> <label for="by-text">Text message</label></div>Why this fix: Use native HTML first
Every option is labelled, so each one has a name. But the question is a paragraph beside the options, not their group name, so a screen reader reads "Yes, radio button" and never the question.
The fieldset is the group and its legend is the group's name, so a screen reader says the question as focus enters the group, roughly "Leave the parcel if no one is home?, grouping, Yes, radio button". The labels stay, so each option still has its own name. Reset the fieldset's default border and padding in CSS if the design doesn't want them; the meaning stays.
Both make the printed question the group's name and pass 1.3.1. Use a fieldset and legend: they do the same job with plain HTML and no ids to keep in step, and they also work where ARIA support is patchy, such as reader views and older assistive technology. Keep the group role for markup you can't restructure, and replace it with a fieldset when you can.
A legend names the group, not the fields. Every option still needs its own label. A legend with bare radio buttons under it, labelled only by text beside them, is announced as the question followed by "radio button" and nothing else. That is the mistake andi:legend-alone reports.
Keep the legend short. Screen readers may repeat the legend for every option in the group, especially in their list of form fields. Put the question in the legend and longer help, such as what "Express" costs, in a hint tied with aria-describedby on the group or the option.
One checkbox needs no group. A single "I agree to the terms" checkbox is named by its label alone. Group checkboxes only when several answer one question.
Styling. Older browsers made fieldset hard to lay out with flex or grid. Current browsers support both, so styling is rarely a reason to drop it today. Set min-inline-size: 0 if a wide child stops the fieldset from shrinking. Keep the legend as the first child, or browsers won't treat it as the legend.
Nested groups. A group inside a group, such as an address inside "Delivery", works but every legend is read in turn. Nest only when the outer question really frames the inner one.
Components. Make the question a required prop of the shared radio group and checkbox group components, and render it as the legend. That way an ungrouped set of options can't be built.
Fixing this with an AI coding assistant? Get this guide as Markdown
Verify the fix
4 checks, no mouse.
Test with: Keyboard, Screen reader, Zoom, Forced colors
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the shared group components change.
Limits
This is a starting pattern, not a guarantee for every application. Screen readers differ in how often they repeat a group name, and some read it only on the first option. Custom radio buttons built from div elements need the full radio pattern, with arrow keys and states, which this guide doesn't cover. Groups inside third-party widgets and payment iframes need the same check. Test the complete journey with your target assistive technology.
This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.