Do not simulate focus without moving real focus
A widget draws its own highlight and never moves the browser's focus, so the page looks focused and the accessibility API has no idea. F79 is the failure technique for that, and a match is a defect rather than a route to a pass. It has two halves, and either one on its own is enough to fail. The focus state can be missing from the accessibility API, or the API can hold the state and never be told when it changes. Partial exposure counts too, which is where most component code lands. A custom menu that reports focus as somewhere inside the menu, without saying which item, has already failed.
How we find it in an audit
Keyboard testing turns this up fast, because we watch two things at once. Whether the highlight moves, and whether document.activeElement moves with it. When those two disagree, the highlight is paint. A screen reader confirms it from the other direction, since a widget that never fires the change event goes quiet while the visible selection walks down the list. Roving tabindex components get the closest look, because that is the pattern that usually exposes the container and forgets the item inside it.
How affected users experience it
A screen reader moves the reading position to whatever holds focus, and a magnifier moves the viewport there, so both of them depend on being told. When the highlight is painted rather than real, the screen reader stays where it was and the magnifier keeps showing the wrong corner of the screen. The user presses Enter on the item they believe is selected, and something else happens instead. That gap between what looks selected and what is selected is the whole of the harm.
Passes vs. fails
Passes
item.tabIndex = -1;
item.focus(); // move DOM focus, then style it with :focus-visibleFails
item.classList.add("focused"); // the highlight moves, real focus never doesHow this gets tested
The W3C publishes test rules that define what a checker looks for here.
- 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
The other techniques filed under this rule
23 guides on this site are filed under 4.1.2 Name, Role, Value. W3C documents this one as a failure of that rule, so it describes a way the rule gets broken rather than a way to pass it.
- ARIA4sufficientGive custom widgets a real ARIA role
- ARIA5sufficientExpose widget state with ARIA attributes
- ARIA14sufficientLabel icon-only controls with aria-label
- ARIA16sufficientName controls from visible text with aria-labelledby
- G10sufficientBuild custom components on accessibility-supported tech
- G108sufficientExpose name, role, and changes through markup
This guide is our interpretation of W3C technique F79: Failure of Success Criterion 4.1.2 due to the focus state of a user interface component not being programmatically determinable or no notification of change of focus state available. W3C publishes its techniques as guidance rather than as the standard, and says so on every one of them. The success criterion is what conformance is measured against, and a technique is one documented way to meet it.