sfw/fix
aria-allowed-attr high

Elements must only use allowed ARIA attributes

An aria-* attribute isn't permitted for that element's role, so the browser drops it and the widget's state never reaches a screen reader.

What you see

Elements must only use allowed ARIA attributes (aria-allowed-attr)
Fix any of the following:
  ARIA attribute is not allowed: aria-checked="true"
<div aria-checked="true" class="toggle">Email alerts</div>

What’s actually happening

axe flags an element carrying an aria-* attribute that its role doesn't support. The browser computes the accessibility tree, sees the attribute isn't valid for that role, and ignores it. So a custom toggle built as <div aria-checked="true"> announces no checked state at all — the screen reader reads "Email alerts" with no on/off, and the user has no idea it's a control. The classic trip-up: a bare div has no role, and an element with no role only accepts the global ARIA attributes, so aria-checked there is invalid even though aria-label on the same div would be fine.

Common causes

  • aria-checked, aria-selected, or aria-expanded on a plain <div>/<span> that was never given the role those states belong to
  • A role and a state that don't match — aria-expanded on role="button" is allowed, but aria-checked on role="link" is not
  • Copying ARIA from a similar-looking widget without checking which states that role actually permits
  • A role typo (role="checkbutton") that leaves the real role unset, so its states read as disallowed
  • Framework props that emit aria-* attributes regardless of the role the component ends up rendering

How to fix it

  1. Add the role the attribute belongs toIf the element genuinely is a checkbox, give it role="checkbox" so aria-checked becomes valid — and then add everything else that role requires (a checkbox needs aria-checked set and keyboard support). The attribute was never wrong; the missing role was.
  2. Use the native element and skip ARIA entirely<input type="checkbox"> exposes checked state, focus, and keyboard handling for free and can't trigger this rule. Reach for role + aria-checked on a div only when no native control fits the design.
  3. Check the role's allowed states in the ARIA in HTML specEvery role lists which states and properties it supports, plus the global attributes any element accepts (aria-label, aria-hidden, aria-describedby). Match each aria-* you set to that list. Anything outside it gets dropped silently — no visible error, just a control that doesn't announce.
  4. Remove ARIA that's there by accidentSometimes the fix is deletion. If a wrapper picked up aria-selected from a copied snippet and isn't actually a tab or option, strip it. An unsupported attribute does nothing useful and only adds noise to the next audit.

Stop it recurring

Build interactive widgets from a vetted component library or headless primitive that pairs each role with its allowed states, instead of hand-adding aria-* to divs.

Related errors