( Robust / WCAG 4.1.2 )
ARIA attribute is not allowed for this role
What is this issue?
An element has a role (either explicit, via the role attribute, or implicit, from the native HTML element itself) paired with an ARIA state or property that role’s specification doesn’t list as supported. Each ARIA role publishes its own set of allowed states and properties: checkbox supports aria-checked, slider supports aria-valuenow, and so on, and an attribute outside that role’s list is invalid on it.
This differs from an attribute name that’s simply misspelled: the attribute name itself is real and spelled correctly, but it’s paired with a role that was never meant to carry it. A role="button" with aria-checked is exactly this failure: aria-checked is a genuine ARIA property, just not one the button role’s specification supports.
Why does this matter?
When an ARIA attribute isn’t on its role’s supported list, the browser doesn’t pass it through to the accessibility tree with a warning; it silently omits it, as if it were never written. The developer sees the attribute sitting in the DOM in dev tools and assumes it’s working; the screen reader user gets nothing.
The failure is quiet by design, which makes it dangerous. A toggle button built with role="button" and aria-checked to track its on/off state looks correct in every code review: the attribute is spelled right, the value updates on click, the visual state changes. Only a screen reader user discovers the gap, and only because the button never announces “checked” or “not checked” no matter how many times they activate it.
Who is affected?
- Screen reader users: never hear the state the attribute was meant to convey, since it’s stripped before it reaches the accessibility tree, leaving them unable to tell whether a toggle, expander, or selector control is currently on, open, or selected.
- Cognitive disabilities: lose a state cue (checked, expanded, pressed) that would otherwise confirm an action succeeded, increasing uncertainty about whether an interaction actually registered.
What users experience
Dmitri uses JAWS on Windows in a project management tool to mark tasks as complete. The task row is a <div role="button"> with aria-checked toggled by a click handler, a pattern copied from an older component before anyone confirmed which attributes button actually supports. JAWS announces “Task complete, button” every time, with no checked or unchecked state at all, no matter how many times Dmitri activates it. He has to open the task and check its description for a status field to confirm whether his click actually registered.
How do I fix it?
Match the role to the attribute it’s meant to carry, most often by switching to role="checkbox" or the applicable state-bearing role instead of a plain role="button". This works because the corrected role’s specification explicitly lists that attribute as supported, so the browser passes it through to the accessibility tree instead of discarding it.
If the control genuinely is a simple button with no persistent state, use aria-pressed instead of aria-checked; aria-pressed is the state-bearing property button actually supports, built for exactly this toggle-button pattern. Check the target role’s published supported-attribute list in the WAI-ARIA specification whenever you’re unsure which state property pairs with which role, rather than guessing from an attribute name that sounds plausible.
Code Examples
<div role="button" aria-checked="true">Save document</div><!-- Method 1: aria-pressed is the state button actually supports -->
<div role="button" aria-pressed="true" tabindex="0">Save document</div>
<!-- Method 2: switch to checkbox if the control is genuinely a toggle -->
<div role="checkbox" aria-checked="true" tabindex="0">Save document</div>Method 1 keeps the control as a button but swaps the attribute to aria-pressed, which the button role’s specification explicitly supports for exactly this toggle-state use case. Method 2 keeps aria-checked but changes the role to checkbox, the role that attribute was designed for. Either fix reconnects the state to a role that will actually pass it through to the accessibility tree; the choice depends on which role better matches how the control behaves for a mouse and keyboard user.
Common Mistakes
Mistake: “The attribute name is spelled correctly, so it must be working.” Correct spelling only proves the attribute is a real ARIA property, not that it’s valid on this specific role. aria-checked and role="button" are each individually valid; the combination of the two together is what fails, because button’s specification doesn’t include aria-checked in its supported list.
Mistake: “I can see the attribute updating in dev tools, so assistive technology must see it too.” The Elements panel shows the raw DOM, not the accessibility tree the browser actually builds for assistive technology. An attribute unsupported by the role is stripped during that translation step, so it can look perfectly present in dev tools while being completely invisible to a screen reader.
Mistake: “If one attribute doesn’t work on this role, I’ll just add more attributes to compensate.” Adding aria-selected or aria-expanded alongside an already-unsupported aria-checked doesn’t create a fallback: each attribute is checked independently against the role’s list, so stacking more unsupported properties on the same role just produces more silently dropped attributes, not a working state.
How RedFlag Detects This
Automated: axe-core rule, runs on every scan. RedFlag calls axe-core’s aria-allowed-attr rule as part of every scan, restricted to the WCAG 2.0/2.1/2.2 A and AA rule set. The rule resolves each element’s role (explicit via the role attribute or implicit from the native HTML element) then checks every aria-* attribute present against that role’s published list of supported states and properties, flagging any attribute the role doesn’t support.
False negative: the rule confirms an attribute is permitted on a role, not that its value is being kept in sync with the control’s real state: a checkbox with aria-checked correctly present can still announce the wrong checked/unchecked value if the click handler forgets to update it. False positive: none typical for this check, since matching an attribute against a role’s fixed supported list is a binary lookup axe-core evaluates reliably. Manual step: for any flagged element, confirm what state the control needs to expose and pick the role whose supported-attribute list actually includes it, rather than removing the attribute and losing the state entirely.
Manual Testing
- Open the page in Chrome or Firefox with NVDA or VoiceOver running.
- Tab to each custom control (toggle, checkbox, expandable section) built from a
<div>or<span>rather than a native form element. - Activate the control and listen for a state announcement (“checked,” “pressed,” “expanded”) immediately after its name and role.
- If the visual state changes but the screen reader announces nothing new, or repeats the same announcement regardless of state, the underlying ARIA attribute is likely unsupported on that role.
- Open the browser’s accessibility inspector (Chrome DevTools → Elements → Accessibility pane) and confirm the computed properties list includes the state attribute you expect; if it’s missing there despite being present in the DOM, the role doesn’t support it.
Related WCAG Success Criteria
4.1.2 Name, Role, Value: Every interface component must expose its current state to assistive technology, and that exposure has to happen through an attribute the component’s role actually supports. An unsupported attribute fails this criterion on the “value” requirement specifically, since the state never reaches the accessibility tree at all.
Related Issues
ARIA role is invalid is the prerequisite check: this rule assumes the role itself is spelled correctly and real; an invalid role produces a different, more foundational failure.
ARIA attribute is prohibited for this role covers the stricter, related case where a handful of roles explicitly forbid even normally-global attributes like aria-label, rather than simply lacking support for a role-specific state.
ARIA attribute is not valid for the current role value covers attributes that are allowed on a role only under a specific condition, such as inside a treegrid, rather than being unconditionally unsupported.
Required ARIA attribute is missing is the mirror-image failure: a role that requires a specific attribute and doesn’t have it, instead of carrying an attribute it never should have had.
Element uses a deprecated ARIA role and ARIA attribute name is not valid are the two other most common ways a role-and-attribute pairing goes wrong in the same audit pass.
References
- W3C Understanding 4.1.2: Name, Role, Value
- WAI-ARIA in HTML: Document conformance requirements
- MDN: ARIA attributes
- ARIA Authoring Practices Guide
Frequently asked questions
Does axe-core catch this automatically, or does it need manual review?
It is fully automated. RedFlag runs axe-core's aria-allowed-attr rule on every scan, and matching an attribute against a role's supported-attribute list is a mechanical lookup with no ambiguity, so no manual confirmation step is needed to know the attribute-role pairing itself is invalid.
Do global ARIA attributes like aria-label always work on any role?
Mostly, but not always. Attributes such as aria-label, aria-describedby, and aria-hidden are treated as globally supported across nearly every role, unlike role-specific states such as aria-checked or aria-expanded. A small set of roles explicitly prohibit even the global naming attributes, which is a separate, related check.
What happens in the browser when an ARIA attribute is not allowed for a role?
The browser's accessibility tree simply omits it. The attribute still sits in the DOM and is visible in dev tools, but it never reaches the accessibility API, so no assistive technology ever sees the state or property it was meant to convey.
Does this rule apply to native HTML elements, not just elements with a role attribute?
Yes. Every HTML element has an implicit ARIA role even without a role attribute written in the markup, and that implicit role has its own supported-attribute list. A native checkbox input already has an implicit checkbox role, so adding an attribute that role does not support fails the same way as it would on a div with an explicit role.
Is aria-allowed-attr the same check as aria-prohibited-attr?
No, though they are closely related. aria-allowed-attr checks whether a role-specific state or property is on the correct role's supported list. aria-prohibited-attr specifically checks a smaller set of roles, like presentation and generic, that explicitly forbid otherwise-global naming attributes such as aria-label.