ARIA stands for Accessible Rich Internet Applications. It is a set of HTML attributes, standardised by the W3C as WAI-ARIA (current version 1.2, published in June 2023), that gives assistive technologies such as screen readers additional information about user interface elements. ARIA becomes necessary where the semantics of native HTML end: a tab interface, an accordion, a custom dropdown or a status message that appears dynamically. The vocabulary consists of three building blocks: roles describe what an element is, states describe its current condition, and properties describe characteristics and relationships. ARIA is powerful and dangerous at the same time. Used correctly it makes complex widgets usable for screen reader users, used incorrectly it actively breaks accessibility, which is why the most important rule of ARIA is to prefer native HTML elements whenever they can do the job.
What does ARIA stand for and why does it exist?
HTML has rich built-in semantics: a button is announced as a button, a nav is a navigation, a checked checkbox reports its state on its own. Screen readers read all of this from the accessibility tree that the browser builds from your markup. The problem starts with everything HTML has no element for. There is no native tab panel, no accordion, no toast notification. Developers build these out of divs and spans, and for a screen reader user a div-based accordion is just silence: no name, no role, no state.
WAI-ARIA fills exactly this gap. It lets you tell assistive technology what your custom widget is and what it is doing, without changing anything about how the page looks or behaves for everyone else.
Roles, states and properties: the three building blocks of ARIA
- Roles define what an element is.
role="dialog",role="tablist",role="alert". A role is a promise to the user: this thing will behave like a dialog. - States describe the current, changeable condition of an element.
aria-expanded="true",aria-checked="false",aria-disabled="true". States change while the user interacts, and your JavaScript must keep them in sync. - Properties describe characteristics and relationships that rarely change.
aria-labelledbypoints to the element that names this one,aria-controlspoints to the element this one operates,aria-requiredmarks a mandatory field.
The distinction between states and properties is academic in daily work, both are just attributes. The mental model that matters: role says what it is, everything else says what it is called, what it is doing and what it belongs to.
The first rule of ARIA: do not use ARIA
The W3C document Using ARIA opens with a rule that sounds like a joke but is entirely serious: if a native HTML element with the semantics and behaviour you need already exists, use it instead of repurposing another element and adding ARIA. Compare these two ways to build a button:
<!-- Looks like a button to sighted users, is a dead div for everyone else -->
<div class="btn" onclick="save()">Save</div>
<!-- Everything included: role, keyboard support, focus -->
<button type="button" onclick="save()">Save</button>To fix the div version you would need role="button", tabindex="0" and extra JavaScript for Enter and Space. The native element does all of that for free and will keep doing it in browsers you have never tested. The same logic applies to links, checkboxes, form fields and headings.
There is a sobering data point behind this rule. WebAIM analyses the top million home pages every year, and its reports consistently find that pages using ARIA have more detected accessibility errors on average than pages without it. That is not because ARIA is bad, but because it is so frequently applied incorrectly. No ARIA is better than broken ARIA.
The most important ARIA attributes explained
- aria-label: gives an element its accessible name directly. The classic use case is an icon-only button:
aria-label="Close"on the X of a modal. - aria-labelledby: points to the ID of another element whose visible text becomes the name. Preferred over aria-label when a visible label exists, because the two cannot drift apart.
- aria-describedby: points to additional descriptive text, typically a hint or an error message below a form field.
- aria-hidden="true": removes an element and its children from the accessibility tree. Right for decorative icons, dangerous on anything focusable.
- aria-expanded: signals on the trigger whether the controlled area is open or closed. The backbone of accordions, dropdown menus and mobile navigation.
- aria-controls: connects a trigger to the element it operates.
- aria-live: turns an element into a live region whose content changes are announced automatically.
politewaits for a pause,assertiveinterrupts immediately and should be reserved for genuinely urgent messages. - aria-current: marks the current item in a set, for example
aria-current="page"on the active navigation link. - aria-required and aria-invalid: communicate mandatory fields and validation failures in forms. With native HTML validation,
requiredalone already covers the first part.
What are ARIA landmark roles?
Landmarks divide a page into named regions that screen reader users can jump between directly, the way sighted users visually scan a layout. The good news: modern HTML elements create most landmarks implicitly, so in a well-structured document you rarely write these roles by hand.
headermaps to the banner landmarknavmaps to navigationmainmaps to main, and there should be exactly one per pageasidemaps to complementaryfootermaps to contentinfoformandsectionbecome form and region landmarks when they have an accessible name
One habit worth adopting: if a page has two navigations, name them apart with aria-label="Main menu" and aria-label="Footer menu". Hearing navigation twice with no distinction helps nobody.
Practical ARIA examples: accordion and live region
A minimal accessible accordion header shows how the pieces work together. The button carries the state, the panel is referenced by ID, and JavaScript flips both on click:
<h3>
<button aria-expanded="false" aria-controls="panel-shipping">
Shipping and returns
</button>
</h3>
<div id="panel-shipping" hidden>
<p>We ship within 2 to 4 business days...</p>
</div>And a live region for feedback that appears without a page reload, for example after an add-to-cart action or a filtered search:
<div aria-live="polite" class="visually-hidden" id="status"></div>
<script>
document.getElementById('status').textContent = '12 products found'
</script>Without the live region, a screen reader user filters a product list and hears nothing at all. With it, the result count is announced the moment it changes. Small attribute, big difference.
Common ARIA mistakes to avoid
- aria-hidden="true" on focusable elements: the element disappears from the accessibility tree but stays in the tab order. Keyboard users land on a ghost. This is one of the most frequent ARIA errors in the wild.
- Redundant roles:
role="button"on abuttonorrole="navigation"on anavadds noise and shows that the markup was not understood. - Roles without behaviour:
role="tab"promises arrow key navigation. If your JavaScript does not deliver it, the role makes things worse than no role, because it raises expectations the widget cannot meet. - Stale states: an
aria-expandedthat stays false forever because nobody updates it in the click handler. Screen reader users hear collapsed while staring at an open panel. - aria-label on plain text elements: on a div or span without a role, aria-label is ignored by most assistive technology. It is not a general-purpose tooltip.
- Overusing assertive live regions: if every cart update, cookie notice and newsletter box interrupts the user, the truly important announcements drown.
ARIA in WordPress themes and plugins
WordPress core is in decent shape: the navigation block manages aria-expanded on submenu toggles, the screen-reader-text CSS class for visually hidden labels is a long-standing convention, and core form components ship with sensible attributes. The trouble usually arrives with what gets installed on top. Page builders, slider plugins, mega menus and popup tools are the places where div soup with missing or broken ARIA piles up. When you evaluate a theme, the accessibility-ready tag in the WordPress theme directory is a genuine signal, since those themes go through a review against defined criteria. For everything else, the ARIA Authoring Practices Guide documents proven patterns for almost every widget you will ever build, with working keyboard behaviour included.
How does InspectWP check ARIA usage?
InspectWP examines your rendered pages as part of its accessibility analysis and flags ARIA-related problems automated tooling can reliably detect: invalid role names, ARIA attributes that are not allowed on the element they sit on, references to IDs that do not exist, focusable elements hidden with aria-hidden and interactive elements without an accessible name. Findings are grouped by severity, so a broken name on your main navigation ranks above a redundant role in the footer. Since screen reader behaviour ultimately decides what works, treat the report as your fast, repeatable first pass, and verify the critical flows with a real screen reader afterwards.