I keep finding aria-label on buttons that say what they do. Somebody wanted to make the component more accessible and added more accessibility. The instinct makes sense. The browser now has two names to choose from.
Browsers give interactive elements an accessible name so screen readers and voice-control software can identify them. A screen reader might announce “Save, button.” In that sentence, “Save” is the name.
The button text can handle the job on its own:
<button type="button">Save</button>
Adding aria-label="Save" gives me the same answer twice and one more string that can drift later.
My first move is boring HTML
I start by checking whether HTML has an element for the job. A button brings button semantics and keyboard behavior. A label connects text to a form control. I get all of that before ARIA enters the file.
<label for="email">Email address</label>
<input id="email" name="email" type="email">
That visible label gives the input a name and gives the user a larger area to click. The W3C guidance on accessible names recommends the same approach: visible text backed by native HTML.
ARIA can describe a div as a button. I still have to add focus handling and keyboard support. The browser has done that work for a real button, so I tend to let it.
aria-label needs one job
I reach for aria-label when a control has no useful text. An icon-only close button is a good example:
<button type="button" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
The × gives a visual cue, and aria-label gives the button its name. I hide the symbol from the accessibility tree because hearing “multiplication sign, Close, button” is not helping anyone.
I use the same idea when a page has more than one navigation landmark:
<nav aria-label="Primary">
...
</nav>
<nav aria-label="Footer">
...
</nav>
Now a screen reader can list “Primary navigation” and “Footer navigation” instead of handing the user two mystery navs.
One button can end up with two names
Browsers give aria-label priority when they calculate the accessible name. If I add one to a button with visible text, the ARIA value can replace the words on screen.
<button type="button" aria-label="Delete item">
Remove
</button>
A sighted user sees “Remove.” A screen reader user hears “Delete item.” Someone using voice control says “Click Remove” and may get no match. I made one button answer to two names.
The WCAG guidance for Label in Name says the accessible name should contain the visible label. In this case, I delete the extra attribute and let the button text name itself:
<button type="button">Remove</button>
If the control needs more context, I keep the visible word inside the accessible name:
<button type="button" aria-label="Remove Jordan from the team">
Remove
</button>
“Remove” now appears on screen and in the accessible name. The extra context can help a screen reader user without breaking voice control.
Placeholders make bad labels
Placeholder text disappears as soon as someone types. It tends to show up in a low-contrast gray that creates another problem during an accessibility audit. I give the field a label that sticks around and use a description for the extra instruction.
<label for="password">Password</label>
<input
id="password"
name="password"
type="password"
aria-describedby="password-help"
>
<p id="password-help">Use at least 12 characters.</p>
The label names the input. aria-describedby connects the password rule without cramming the whole instruction into the name.
I check what the browser built
I check the accessibility tree in browser developer tools and look at the computed name and role. Then I tab through the page and use the control without a mouse. An automated check can catch a missing name. It will accept “Action button” without asking why anyone would call it that.
For a custom interaction, I compare my version with the matching pattern in the ARIA Authoring Practices Guide. ARIA gives me enough control to misrepresent the interface, so I want to know when I have wandered away from the browser’s built-in behavior.
My check is short:
- Did I use the native element?
- Does the visible text provide the name?
- If I need
aria-label, does it match the words on screen? - Did I check the computed name and keyboard behavior?
I want the control to have one useful name no matter how someone finds it. Most of the time, HTML gets me there before I type aria- anything.