Forms Rule

ARIA toggle fields must have an accessible name aria-toggle-field-name

Elements with role="switch", role="checkbox", role="radio", role="menuitemcheckbox" or role="menuitemradio" are toggles: they are on or off, checked or not. Screen readers announce the role and the state, but the person also needs to know what is being toggled. That name has to come from the element's text content, aria-label or aria-labelledby. Without it, they hear switch, off, and have to guess.

Websight reports this as ARIA toggle fields must have an accessible name

Who it affects

Someone booking cinema tickets with a screen reader reaches a styled switch and hears switch, off. It is the toggle for wheelchair-accessible seating, but nothing says so, and the next switch is for a hearing loop.

Someone using voice control cannot say click accessible seating because the switch has no name, and has to resort to a numbered overlay to reach it.

Someone with a cognitive disability sees three identical pills in a row with text somewhere nearby and cannot be sure which pill belongs to which option.

Broken versus fixed

Both examples are live and rendered in a sandboxed frame. The broken one is deliberately broken.

Broken

Tab to the first pill with a screen reader on: switch, on. The text beside it is not connected, so the name is missing.

Fixed

Announced: Wheelchair-accessible seating, switch, on. Then Hearing loop seats, switch, off.

Show the markup behind both examples
Broken
<style>body{font-family:system-ui;padding:16px;margin:0}.row{display:flex;align-items:center;gap:12px;margin-bottom:10px}.sw{width:44px;height:24px;border-radius:12px;border:0;background:#999;position:relative;cursor:pointer}.sw[aria-checked=true]{background:#2a8f4a}.sw::after{content:"";position:absolute;top:2px;left:2px;width:20px;height:20px;border-radius:50%;background:#fff}.sw[aria-checked=true]::after{left:22px}.sw:focus{outline:3px solid #1e5aa8;outline-offset:2px}</style>
<div class="row"><button class="sw" role="switch" aria-checked="true"></button><span>Wheelchair-accessible seating</span></div>
<div class="row"><button class="sw" role="switch" aria-checked="false"></button><span>Hearing loop seats</span></div>
Fixed
<style>body{font-family:system-ui;padding:16px;margin:0}.row{display:flex;align-items:center;gap:12px;margin-bottom:10px}.sw{width:44px;height:24px;border-radius:12px;border:0;background:#999;position:relative;cursor:pointer}.sw[aria-checked=true]{background:#2a8f4a}.sw::after{content:"";position:absolute;top:2px;left:2px;width:20px;height:20px;border-radius:50%;background:#fff}.sw[aria-checked=true]::after{left:22px}.sw:focus{outline:3px solid #1e5aa8;outline-offset:2px}</style>
<div class="row"><button class="sw" role="switch" aria-checked="true" aria-labelledby="wc"></button><span id="wc">Wheelchair-accessible seating</span></div>
<div class="row"><button class="sw" role="switch" aria-checked="false" aria-labelledby="hl"></button><span id="hl">Hearing loop seats</span></div>

Test it by hand in two minutes

  1. In DevTools, search the Elements panel for role="switch", role="checkbox" and role="radio". Each match needs visible text inside it, an aria-label, or an aria-labelledby that points at text.
  2. Select the toggle in DevTools and open the Accessibility pane. Check the Name row is filled in and the Checked row changes when you click the toggle.
  3. Turn on VoiceOver (Cmd+F5) or NVDA and Tab to each toggle. You should hear the name, the role and the state, in that order, for example Hearing loop seats, switch, off.
  4. Press Space on the toggle and listen. The state should be announced as changed, and the name should stay the same.

The fix

Before
<button role="switch" aria-checked="false"></button>
<span>Hearing loop seats</span>
After
<button role="switch" aria-checked="false" aria-labelledby="hl"></button>
<span id="hl">Hearing loop seats</span>

Point the toggle at the visible text so both agree. If the text is inside the button already, it counts as the name and nothing else is needed.

Text inside the toggle

Before
<div role="checkbox" aria-checked="false" tabindex="0"></div>
Remember me
After
<div role="checkbox" aria-checked="false" tabindex="0">Remember me</div>

Putting the text inside the element names it automatically and makes the text clickable.

Icon-only toggle

Before
<button role="switch" aria-checked="false" class="bell"></button>
After
<button role="switch" aria-checked="false" class="bell" aria-label="Email reminders"></button>

Name the thing being switched, not the state. The state is announced separately from aria-checked, so do not write aria-label="Reminders off".

Use a native checkbox

Before
<div role="checkbox" aria-checked="false" tabindex="0"></div>
After
<label>
  <input type="checkbox" name="remember"> Remember me
</label>

A real checkbox can be styled to look like a switch and handles name, state and keyboard for free.

Common mistakes

  • Placing the text next to the toggle in a span with nothing linking them.
  • Writing the state into the name (aria-label="Notifications on"), so it is wrong half the time.
  • Using a label element with a for attribute pointing at a div or button; label only works on form controls.
  • Naming all the toggles the same thing, such as aria-label="toggle".
  • Forgetting aria-checked, so the toggle has a name but never announces whether it is on.

WCAG criteria this rule maps to

axe-core tags this rule as WCAG 2.2 level A. It is one of the checks for:

The scanner can see a toggle role with no text content, aria-label, aria-labelledby or title. It cannot tell whether the name makes sense, or whether the state is actually updated when the toggle is pressed. Automated tools find only part of the accessibility problems on a page; a pass on this rule is not a pass on the criterion.

Scan your own page for this and 63 other checks

Open any page in Chrome, click Websight, and get a score out of 100 with every issue explained and a draft fix snippet per element.

Add Websight to Chrome

Free scans, no account, nothing leaves your computer. Automated tools find only part of the problems; the extension says so on every report.