# Radio buttons and checkboxes without a group name

Source: https://easeweb.dev/learn/field-groups
Topics: Forms > Radio buttons and checkboxes are grouped (WCAG 1.3.1)
The fix: Tie each question to its options in the markup. Either wrap the options in a fieldset and make the question its legend, or keep the existing wrapper and give it role="radiogroup" or role="group" with aria-labelledby pointing at the question. Keep a label on every option as well.
Test with: keyboard, screen reader, zoom, forced colors
References: https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships.html https://www.w3.org/WAI/WCAG22/Techniques/html/H71 https://www.w3.org/WAI/tutorials/forms/grouping/ https://www.w3.org/WAI/ARIA/apg/patterns/radio/ https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset

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.

## What happens

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.

## Why it fails

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.

## Who is affected

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.

## What automation and AI miss

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.

## Before: questions as plain text above the options

```html
<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>
```

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.

## After: a fieldset and legend

```html
<fieldset class="options">
  <legend class="question">Leave the parcel if no one is home?</legend>
  <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>
</fieldset>

<fieldset class="options">
  <legend class="question">Send me updates by</legend>
  <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>
</fieldset>
```

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.

## After: a group role pointing at the question

```html
<p id="leave-q" class="question">Leave the parcel if no one is home?</p>
<div class="options" role="radiogroup" aria-labelledby="leave-q">
  <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 id="updates-q" class="question">Send me updates by</p>
<div class="options" role="group" aria-labelledby="updates-q">
  <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>
```

When a layout component or template won't let the wrapper become a `fieldset`, give the question an `id` and point the wrapper at it. `role="radiogroup"` suits a set of radio buttons and `role="group"` a set of checkboxes. The group is then named by the printed question, as with a legend. The ids must stay unique on the page, so generate them in the component rather than typing them by hand.

## Which option to use

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.

## Implementation decisions

**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.

## Verify the fix

1. In the browser's accessibility tree, check each set of options sits inside a group whose name is the printed question, and each option has its own name.
2. With a screen reader, Tab into each group from above and with Shift + Tab from below, and check the question is announced before the first option you land on.
3. In browse mode and in the screen reader's list of form fields, check options with the same word, such as two "Yes" options, can be told apart.
4. At 200% zoom and in forced colors, check each question is still visible next to its options.

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.
