Website problems
Invalid ARIA attributes
ARIA attributes describe roles, states and properties to assistive technology when native HTML cannot. Because they override what the browser would otherwise report, an incorrect ARIA attribute does not degrade gracefully — it replaces accurate information with inaccurate information. The three failures that recur are references pointing at elements that do not exist, roles and values that are not valid, and interactive elements hidden from assistive technology while remaining reachable by keyboard.
The first rule of ARIA
The specification's own guidance is that if a native HTML element or attribute provides the semantics you need, use it rather than repurposing another element with ARIA added.
`<button>` is focusable, activates on Enter and Space, and announces as a button, with no attributes at all. A `<div role="button">` announces as a button and does none of the rest until you implement it.
This matters because most invalid ARIA is found on elements that did not need ARIA. The fix is frequently to delete the attributes and use the right element.
The corollary is the reason this problem is worth its own page: no ARIA is a page assistive technology reads with native semantics. Wrong ARIA is a page it reads incorrectly, confidently.
Broken references
`aria-labelledby`, `aria-describedby`, `aria-controls` and `aria-owns` all take element IDs. An ID that does not exist on the page means the attribute resolves to nothing.
The control then falls back — often to no accessible name at all, which is the same outcome as omitting the label entirely, reached by a longer route.
Causes: a component copied between pages where the target element was not copied, an ID changed during a refactor, a framework generating unique IDs per render while the reference is hardcoded, or a reference to an element inside a modal that is not in the DOM until the modal opens.
This is the most mechanically detectable ARIA failure, because it is a lookup that either resolves or does not.
Invalid roles and values
A role that is not in the specification — a typo, or an invented name — leaves the element with its native semantics and a misleading attribute in the markup.
A state attribute with the wrong value type: `aria-expanded="yes"` instead of `"true"`, or a boolean attribute given a number.
Required attributes omitted: `role="checkbox"` without `aria-checked`, `role="slider"` without `aria-valuenow`, `role="tab"` outside a `tablist`.
Roles applied to elements that cannot carry them, such as a presentational role on a focusable element.
And states that are set once and never updated — `aria-expanded="false"` on a menu that opens, which is the commonest of all and the hardest to see in static markup.
Hidden interactive elements
`aria-hidden="true"` removes an element and its subtree from the accessibility tree. It does not remove it from the page or from the tab order.
An interactive element inside an `aria-hidden` subtree is therefore reachable by keyboard and invisible to a screen reader: focus lands somewhere the user is told nothing about.
This happens most often around modals, where the background is hidden from assistive technology but its focusable elements remain in the tab order, and around off-screen menus hidden with `aria-hidden` rather than with `display: none` or the `inert` attribute.
The correct tool for 'not available right now' is `inert`, which removes an element from both the accessibility tree and the tab order, or `display: none`, which removes it from everything.
How to check it yourself
For broken references, in the console: for each element with `aria-labelledby` or `aria-describedby`, check that every ID it names resolves with `document.getElementById`.
For hidden interactive elements: `[...document.querySelectorAll('[aria-hidden="true"]')].flatMap(el => [...el.querySelectorAll('a,button,input,select,textarea,[tabindex]')])` returns the focusable elements inside hidden subtrees.
Use the browser's accessibility tree view to see what assistive technology actually receives — it applies the ARIA and shows the result, which is faster than reasoning about the attributes.
Then test the components by keyboard. State attributes that never update are only visible in use.
How VeriFixScan detects it
`accessibility.aria_validity` reports roles and attribute values that are not valid according to the specification, with the element and the page.
`accessibility.aria_references` resolves every ID-referencing ARIA attribute against the document and reports the ones that point at nothing.
`accessibility.aria_hidden` reports interactive elements inside `aria-hidden` subtrees — the case where keyboard reachability and assistive-technology visibility disagree.
All three run against the served HTML, which means the static structure. A state attribute that is correct at load and never updated afterwards is outside what any single-document check can see.
Frequently asked questions
- Is wrong ARIA worse than no ARIA?
- Yes. Native HTML semantics are reported accurately by default; ARIA overrides them. An incorrect attribute replaces correct information with incorrect information, which is why the specification's first rule is to prefer native elements.
- Does aria-hidden remove an element from the tab order?
- No. It removes it from the accessibility tree only. A focusable element inside an aria-hidden subtree can still be reached by Tab, and the user is told nothing about it. Use inert or display: none instead.
- Can I add role="button" to a div?
- You can, and then you must implement focusability, Enter and Space activation and the disabled state yourself. A <button> provides all of it. The role alone announces a button that does not behave like one.
Sources
Related
VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.
Scan a website