You’ve probably seen markup like this many times:
<button role="button">
Save
</button>
And at first glance, it doesn’t seem to do anything useful.
That instinct is right. A native <button> already has a button role, so adding role="button" changes nothing.
Where is this behaviour actually defined?
This is defined in the Core Accessibility API Mappings 1.2 specification.
When a host language declares a WAI-ARIA attribute to be in direct semantic conflict with a native attribute for a given element, user agents MUST ignore the WAI-ARIA attribute and instead use the host language attribute with the same implicit semantic.
Here’s a plain language breakdown of that sentence:
If HTML already provides a semantic meaning, ARIA does not override it. The browser keeps the native semantics and ignores the ARIA.
This rule exists to prevent assistive technologies from receiving conflicting or duplicate information.
Why does this rule exist?
The specification requires browsers to ignore role="button" on a native <button>.
This rule exists because a native <button> already provides everything needed:
- an implicit ARIA role of
button - built-in keyboard behaviour
- built-in states such as disabled
- a well-defined mapping to accessibility APIs
Adding role="button" does not add clarity or extra information. It simply restates what is already there.
The broader lesson
This example highlights a common point of confusion about how ARIA works.
ARIA isn’t meant to be added everywhere to improve accessibility.
It should only be used to:
- Fill gaps where native HTML semantics are missing.
- Provide accessible names or descriptions when HTML alone is not enough.
- Support interaction patterns that HTML doesn’t provide on its own.
- Intentionally replace native semantics when building fully custom widgets.
Five rules of ARIA
The five rules of ARIA help explain when ARIA is useful, and when native HTML should be left alone.
First Rule of ARIA Use
If you can use a native HTML element [HTML51] or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so.
In our example, the <button> has everything built in:
- correct roles
- correct states
- correct keyboard interaction
- correct accessibility API mappings
Second Rule of ARIA Use
Do not change native semantics, unless you really have to.
Adding role="button" to a <button> attempts to restate or override something that is already correct.
Third Rule of ARIA Use
All interactive ARIA controls must be usable with the keyboard.
A native <button> already supports:
- ENTER and SPACE keystrokes
- focus
- disabled state
ARIA does none of that.
Fourth Rule of ARIA Use
Do not use
role="presentation"oraria-hidden="true"on a focusable element.
Though important, this rule is not relevant to our example.
Fifth Rule of ARIA Use
All interactive elements must have an accessible name.
Adding a role to a <button> does not solve this problem. Instead, we need to make sure the <button> has a meaningful visible text label and accessible name.
Conclusion
The best accessibility practice is to use native HTML elements wherever possible.
ARIA should only be used when native semantics are missing, insufficient, or need to be intentionally replaced.
Related articles
How aria-labelledby really works
How aria-labelledby works, including naming precedence, multiple references, hidden content, broken IDs, and shadow DOM boundaries.
Tests for aria-labelledby and aria-describedby
A series of tests to determine how hidden content is used by aria-labelledby and aria-describedby.
Did you know some ARIA roles remove child semantics?
A series of tests to determine how hidden content is used by aria-labelledby and aria-describedby.