Demo
What Aria actually does.
Every example below is real output captured from the published @aria-a11y/cli@0.2.0 running against these exact snippets — the diagnostics and the fixed code are verbatim, not hand-typed to look plausible. It’s static on purpose: a live in-browser approximation could drift from the CI-verified rule behaviour, and for a tool whose whole claim is “provably identical everywhere,” a demo that might show wrong output is worse than no demo.
Redundant role
no-redundant-role · format tier — auto-fixed
export const A = () => <button role="button">Save</button>;export const A = () => <button>Save</button>;aria check · error
Role 'button' is redundant: it matches the implicit role of <button>. Remove it.
Unsupported aria-*
no-unsupported-aria · format tier — auto-fixed
export const B = () => <button aria-checked="true">Go</button>;export const B = () => <button>Go</button>;aria check · error
'aria-checked' is not supported by role 'button' of <button>: WAI-ARIA defines no such property for the role, so user agents ignore it. Remove it.
Icon-only button, no name
control-needs-name · lint tier — reported, never auto-applied
export const C = () => <button><svg /></button>;export const C = () => <button><svg /></button>;aria check · warning
<button> is an interactive control (button) with no accessible name, so assistive technology cannot announce it (control-needs-name; WCAG 2.1 SC 4.1.2). Add text content, aria-label, or an associated <label>. A placeholder is not a name. Aria cannot write it for you.
Placeholder is not a name
control-needs-name · lint tier — reported, never auto-applied
export const D = () => <input type="text" placeholder="Search" />;export const D = () => <input type="text" placeholder="Search" />;aria check · warning
<input> is an interactive control (textbox) with no accessible name, so assistive technology cannot announce it (control-needs-name; WCAG 2.1 SC 4.1.2). Add text content, aria-label, or an associated <label>. A placeholder is not a name. Aria cannot write it for you.
Focusable ghost
aria-hidden-not-focusable · lint tier — reported, never auto-applied
export const E = () => <div aria-hidden="true"><button>x</button></div>;export const E = () => <div aria-hidden="true"><button>x</button></div>;aria check · warning
<div> has aria-hidden="true" but its hidden subtree still contains a focusable element (<button>), a focusable ghost (aria-hidden-not-focusable; WAI-ARIA 1.2). Remove aria-hidden, make the descendant non-focusable (tabindex="-1"), or move it out of the hidden subtree. Aria will not choose.
Run it yourself — the demo is one command away.
The honest interactive version of this page is your own codebase:
npx @aria-a11y/cli check src