Name, Role, Value
Every control has to tell assistive technology three things about itself. What it is called, what kind of control it is, and what state it is in right now. There is a fourth part the short version usually drops, and it matters. Where a value is one the user can set, such as a slider position or a checked box, that value has to be settable from outside rather than only readable. Any change to it has to fire a notification as well. Native HTML gives you the role and the state for free. It does not give you a name for free, because a button with no text and no label has no name at all. A control built out of a div gives you none of the four until somebody writes them in by hand.
Why it matters
This is the contract between your interface and every assistive technology that will ever touch your site. Break it and the dropdown that looks fine on screen is, to a screen reader, a lump of text with no way in. Your screen reader says button. Just button. Now pick the one that empties your cart. Sites built on component frameworks live or die on this rule, because on those sites almost every control started life as a div rather than as a button. And it reaches past screen readers, since a voice-control user activates a control by saying its name, and a control with no name has no name to say.
Who this rule protects
Screen reader users hear nothing useful, or hear only that something is clickable, which is what VoiceOver says about any element carrying a click handler. Either way they cannot tell what the control does, or whether it is a control at all. Voice-control users cannot speak the name to activate it, because there is no name to speak. And a user working a slider through their own assistive technology cannot move it when the value is exposed but not settable. That satisfies half this rule and fails the other half.
How to check it yourself
- Open the accessibility tree in your browser's developer tools, which is the stripped-down version of the page that assistive technology actually reads, and find each custom control on it. Dropdowns, toggles, date pickers and hamburger menus are the usual suspects.
- Check three things on each one. A name that says what it is called, a role that says what kind of control it is, and a state that changes when the control changes, such as expanded, checked or selected.
- Check the fourth thing too, which is whether a value the user can set can actually be set from outside. A slider a screen reader can read and cannot move satisfies half this rule and fails the other half.
- Tab to each control with a screen reader running and confirm what you hear matches what you see. Confirm it announces itself when focus lands on it as well. Whether a control has focus is a state under this rule, so a custom widget that takes focus silently fails on that alone.
- Watch out for the text input whose only label is placeholder text. It usually passes this criterion, because the name computation falls back to the placeholder when nothing else supplies a name. It fails 3.3.2 instead, since a label that disappears when you type is not presented to all users. That difference is the commonest reason a scan report and an auditor disagree about the same field.
- Look inside your buttons. A button with a link or another button in it fails. A control like that is not supposed to expose anything focusable underneath, and there is an automated rule that looks for exactly this.
- Check the iframes. An iframe is a user interface component here too, and an embedded checkout, map or video player with no title is the usual finding.
Failures we see most often
- A div with a click handler and no role is announced as plain text, or skipped altogether. The deeper problem is not silence on arrival. A div does not fire the operating system events a real control fires, so assistive technology may not be told anything happened when the user activates it either.
- An icon-only button announces as button and nothing else, so a user hears that something is pressable without hearing what it does.
- A control has visible label text and no accessible name. It reads fine, and a speech-input user cannot say its name to operate it, because there is no name to say. Voice software can usually reach it another way, by numbering the things on screen or overlaying a grid, and needing the fallback is the finding.
- A custom toggle never says whether it is on or off, because its state lives in a CSS class and assistive technology cannot read CSS classes.
- An aria-label gets added to a bare div to fix a missing name and nothing changes. A div's implicit role is generic, ARIA prohibits naming that role outright, and a browser is entitled to drop the attribute. What the element needs is a role that permits naming, whether that comes from a native element or from an explicit role attribute.
- A phone number is split into three inputs under one group label, and the three parts carry no names of their own. A screen reader user reaches the second box with nothing to say what belongs in it.
- A link contains only an image and the image has no alt text, so the whole link has an empty name and announces as a link to nowhere.
- Two elements share an id and an aria-labelledby points at it, so one control ends up named after the other one's label. Old scan reports file duplicate ids under 4.1.1 Parsing, a criterion WCAG 2.2 removed, and W3C's own note says to report the consequence under whichever criterion it actually breaks. Here, that is this one.
Who this one is for
Read from this rule's own note above, so the grouping and the note cannot disagree.
- Blind and screen reader userspeople who cannot see the screen
- Voice controlpeople who operate the page by speaking to it
The ARIA roles behind this rule
Most failures of this criterion are an ARIA role that was declared without the thing it requires. Of the 94 roles, 34 oblige you to supply a state, a particular parent, or particular children. Every ARIA role, and what each one obliges sets out which.
How this one is tested
We list 15 ACT rules against 4.1.2. Each one defines exactly what a checker looks at, which is how automated tools decide what to flag. Each one also checks a slice, so passing every rule here is not the same as meeting the criterion, and a rule can be proposed rather than approved or need a person to finish it. The note beside each says which.
- Image button has non-empty accessible nameA tool can check this
- Link has non-empty accessible nameA tool can check this
- ARIA attribute is defined in WAI-ARIAA tool can check this
- ARIA state or property has valid valueA tool can check this
- Element with role attribute has required states and propertiesA tool can check this
- Form field has non-empty accessible nameA tool can check this
- Role attribute has valid valueA tool can check this
- ARIA state or property is permittedA tool can check this
- Button has non-empty accessible nameA tool can check this
- Element with aria-hidden has no content in sequential focus navigationA tool can check this
- Element with presentational children has no focusable contentA tool can check this
- Menuitem has non-empty accessible nameA tool can check this
- Summary element has non-empty accessible nameA tool can check this
- Iframe element has non-empty accessible nameA tool can check this
- Iframe elements with identical accessible names have equivalent purposeA tool finds candidates, you decide
How to fix it
- Use the native element wherever one exists. A button, a select and an input carry the right role and keep their own state with no code from you. The one thing they still need is a name, and that comes from their text content or a label.
- When a custom widget is unavoidable, give it a role that permits naming before you worry about the name. An aria-label does nothing on a generic role, whichever order the attributes were typed in, and that is why so many attempted fixes change nothing at all. A native button needs no role attribute, because it already has one that can be named.
- Keep the state attributes in step with what the interface is doing, every time it changes. aria-expanded on a disclosure, aria-checked on a toggle, aria-selected on a tab. A state that is right on load and wrong afterwards is worse than no state at all.
- Give every icon-only control a name that says what it does rather than what it looks like. Open cart, not shopping trolley.
- Watch what an aria-label does to visible text. The name computation prefers an author-supplied label over the element's own content. So an aria-label on a button that already has words in it silently replaces those words, and a voice-control user reading the button aloud no longer reaches it.
- Take focusable things out of buttons and tabs and make them siblings instead, since a control that owns its own children is not meant to expose them separately.
- Give every iframe a title that says what it holds, such as Payment or Store locator, so a screen reader user knows what they have just stepped into.
Step-by-step fix guides (23)
- H44: Attach a real label to every form field
- H91: Use native HTML controls instead of rebuilt ones
- ARIA16: Name controls from visible text with aria-labelledby
- H64: Give every iframe a descriptive title
- H65: Label form fields when a visible label will not fit
- H88: Use HTML the way the spec intends
- ARIA4: Give custom widgets a real ARIA role
- ARIA5: Expose widget state with ARIA attributes
- ARIA14: Label icon-only controls with aria-label
- G10: Build custom components on accessibility-supported tech
- G108: Expose name, role, and changes through markup
- G135: Expose controls through the platform accessibility API
- PDF10: Label every field in your PDF forms
- PDF12: Give PDF form fields a name, role, and value
- F59: Do not build interactive controls from bare divs
- F15: Do not build controls outside the accessibility API
- F20: Do not let text alternatives fall out of date
- F42: Do not emulate links with scripted spans
- F68: Do not ship form controls without accessible names
- F79: Do not simulate focus without moving real focus
- F86: Do not leave parts of a split field nameless
- F89: Do not leave image-only links without a name
- F111: Do not leave labeled controls without a name
Passes vs. fails
Passes
The same control ships as <button aria-label="Open cart"><img src="cart.svg" alt=""></button>, so it carries the button role, an accessible name of Open cart, and its own focus and activation behaviour with no extra code. A control that stays switched on is a different job, and that one needs its state written and kept in step by hand.
Fails
The cart control ships as <div class="btn" onclick="openCart()"><img src="cart.svg"></div>. No role, no name, no state, and to a screen reader it is a picture with nothing to say.
In audits and lawsuits
This is the defining criterion for React and Vue-era sites, where nearly every interactive element started life as a div. Our audits routinely trace complaints such as could not select a size straight back to one of them. It is also the criterion that shows most plainly what a scanner can and cannot do for you. W3C files fifteen test rules under this one criterion, more than under any other, and ten of them name it as the thing they test. Seven of those ten ask only whether a control has an accessible name, and every one of the seven passes on any string that is not empty. Not one of them reads the name and asks whether it describes the control, so a button called button clears the button rule and a link called link clears the link one. Clearing a rule is not clearing the criterion. Six of those seven naming rules are written for links, form fields, image buttons, frames, menu items and summaries, so none of them was ever looking at your button. The rule about elements whose children are meant to be presentational was, and it fails that same button the moment something focusable sits inside it. That is not a complaint about the rules, which are exact about what they test. It is why a green report here proves less than it looks like it proves. And it is why our findings carry the pattern to apply rather than a count of the things a tool noticed.