ARIA Labels & Roles Accessibility Guide 2026: WAI-ARIA for Web Developers
WAI-ARIA (Accessible Rich Internet Applications) is how you make dynamic web content, custom widgets, and complex interfaces accessible to screen reader users. But ARIA is widely misused — adding it incorrectly makes things worse, not better. This guide covers the most important ARIA attributes, roles, and states, with examples of correct and incorrect usage.
The First Rule of ARIA
If you can use a native HTML element or attribute with the semantics and behavior you require, use it instead of repurposing an element and adding ARIA. Native HTML elements are accessible by default. ARIA is a repair mechanism — use it when HTML can't express the semantics you need.
Accessible Names: aria-label, aria-labelledby, aria-describedby
Every interactive element needs an accessible name — the text a screen reader announces when the element receives focus. ARIA provides three main attributes for naming and describing elements:
aria-label
Provides an accessible name as a string value directly in the attribute. The value is read aloud by screen readers instead of the element's visible text content.
Use when: An interactive element has no visible text label — typically icon buttons, close buttons, and navigation elements that rely on visual context.
<svg aria-hidden="true">...</svg>
</button>
aria-labelledby
Points to the ID of another element whose visible text becomes the accessible name. Overrides aria-label if both are present.
Use when: A visible text label already exists on the page that should serve as the accessible name. This keeps the accessible name in sync with the visual label automatically. Multiple IDs can be referenced to concatenate text from multiple elements.
<h2 id="dialog-title">Confirm Deletion</h2>
<p>Are you sure you want to delete this item?</p>
<button>Cancel</button>
<button>Delete</button>
</div>
aria-describedby
Points to supplementary descriptive text. Unlike aria-labelledby, this doesn't provide the accessible name — it provides additional context announced after the name. Used for error messages, hints, and additional instructions.
<input type="email" id="email" aria-describedby="email-error" aria-invalid="true" />
<span id="email-error" role="alert">Please enter a valid email address.</span>
ARIA Landmark Roles
Landmark roles divide the page into named regions that screen reader users can jump between using keyboard shortcuts. Most are automatically applied by HTML5 semantic elements — you don't need to add them explicitly unless using non-semantic elements or needing multiple labeled instances.
| Landmark role | HTML element | Purpose |
|---|---|---|
| banner | <header> | Site header — typically containing logo, site name, and primary nav |
| navigation | <nav> | Navigation links — use aria-label to distinguish multiple navs |
| main | <main> | Primary content area — only one per page |
| complementary | <aside> | Sidebar or supplementary content tangentially related to main |
| contentinfo | <footer> | Footer with copyright, links, legal info |
| search | <form role="search"> | Search form — add aria-label='Site search' |
| form | <form> | Significant form — only applied when form has an accessible name |
| region | <section> | Section with a heading — only a landmark when given an accessible name |
When a page has multiple navigation landmarks (e.g., primary nav and footer nav), distinguish them with aria-label: <nav aria-label='Primary navigation'> and <nav aria-label='Footer navigation'>. Screen readers announce "Primary navigation, navigation" and "Footer navigation, navigation" respectively.
ARIA Live Regions
Live regions announce dynamic content changes to screen readers. Without them, content that appears or updates without a page reload — form validation errors, notifications, search results, chat messages — is silently invisible to screen reader users.
aria-live Values
aria-live="polite"role="status"Waits for the user to finish their current interaction before announcing. Use for most dynamic content — form hints, status updates, non-urgent notifications.
Example use: Form saved successfully. | 3 search results found.
aria-live="assertive"role="alert"Interrupts the user immediately, even if they're in the middle of reading or interacting. Use sparingly — only for time-sensitive critical alerts.
Example use: Session expiring in 60 seconds. | Payment declined.
aria-live="off"Default behavior — changes are not announced. Effectively disables live region behavior.
Live Region Best Practices
- Add the live region to the DOM on page load — before injecting content into it. Some screen readers only register live regions that exist when the page initializes.
- Keep live region content concise. Screen readers read the full text of any changed element, so don't place a large section in a live region.
- Use
aria-atomic="true"to announce the entire region when any part changes (not just the changed part). Useful for status messages where partial announcements would be confusing. - Don't use assertive for anything that isn't genuinely critical. Constant interruptions degrade the screen reader experience significantly.
Common ARIA States and Properties
aria-expandedValues: true / falseWhether a collapsible region (accordion, dropdown, disclosure) is expanded or collapsed. Apply to the trigger element, not the content region.
aria-hiddenValues: true / falseRemoves element from the accessibility tree. Use for decorative icons, duplicate text, and visually redundant UI. Never apply to focusable elements.
aria-invalidValues: true / false / grammar / spellingMarks a form input as having a validation error. Pair with aria-describedby pointing to the error message.
aria-requiredValues: true / falseMarks a form input as required. The HTML required attribute implies this automatically.
aria-disabledValues: true / falseMarks an element as disabled. Unlike HTML disabled, aria-disabled keeps the element in the tab order so screen reader users can discover it and understand why it can't be activated.
aria-selectedValues: true / false / undefinedIndicates which option is selected in a listbox, grid, or tab widget. Not for checkboxes (use aria-checked) or buttons (use aria-pressed).
aria-checkedValues: true / false / mixedState of a checkbox or radio button. mixed is for tri-state checkboxes (e.g., 'select all' in a partially-selected group).
aria-pressedValues: true / false / mixedToggle button state. A button that stays 'on' after being clicked (like Bold in a text editor) should use role='button' aria-pressed='true/false'.
aria-currentValues: page / step / location / date / time / true / falseMarks the current item in a navigation or process. Use aria-current='page' on the active nav link.
aria-modalValues: true / falseTells screen readers that a dialog is modal and should restrict interaction to its contents. Requires focus to be trapped inside the dialog while it's open.
Common ARIA Mistakes to Avoid
Adding role="button" to a <div> doesn't make it a button — you must also handle keydown events, focus management, and visual states. Use <button> instead.
If an element with aria-hidden='true' is in the tab order, keyboard users can focus it but screen readers won't announce anything — creating a silent, confusing tab stop.
Adding role="heading" to an <h2> is redundant. Adding role="list" to a <ul> is redundant. These add noise and can confuse screen readers.
A button with aria-label="Play video" that doesn't update to "Pause video" when clicked creates a mismatch between what screen readers announce and what the control does.
Adding aria-live to a container only works if the container is in the DOM when the page loads. Adding aria-live dynamically at the same time as injecting content often fails.
aria-label overrides visible text completely — aria-label="Click here for more information about pricing" on a "Pricing" link replaces "Pricing", not supplements it. Screen readers will say the aria-label text, ignoring the visible "Pricing".
Sponsored
Also audit your site's full technical health
SEMrush Site Audit checks 130+ issues — missing alt text, broken links, slow pages. Free crawl up to 100 pages, no credit card required.
Frequently Asked Questions
What is the difference between aria-label and aria-labelledby?
aria-label provides an accessible name directly as a string value in the attribute. aria-labelledby points to the ID of another element whose visible text becomes the accessible name. Use aria-labelledby when a visible label already exists on the page — it reuses visible text, keeping the accessible name in sync with the visual UI. Use aria-label when no suitable visible text exists (e.g., an icon button).
When should I NOT use ARIA?
Don't use ARIA when native HTML already provides the semantics. A <button> is already a button — adding role='button' to a <div> requires you to also handle keyboard events, focus, and state manually. The first rule of ARIA is: if you can use a native HTML element with the correct semantics, do that instead. ARIA fixes what HTML can't express — it's not a shortcut.
What are ARIA landmark roles?
ARIA landmark roles define regions of a page that screen reader users can jump between. The main landmarks are: banner (header), navigation (nav), main, complementary (aside), contentinfo (footer), search, form, and region. Most are implicit in HTML5 elements — <header> gets banner, <nav> gets navigation, <main> gets main, <footer> gets contentinfo automatically. Explicit role attributes are needed when using non-semantic elements or when you have multiple instances of the same landmark.
What is an ARIA live region?
An ARIA live region is an area of the page that announces dynamic content changes to screen readers without requiring the user to navigate there. aria-live='polite' waits for the user to finish their current action before announcing. aria-live='assertive' interrupts immediately — use only for critical alerts. role='status' is equivalent to aria-live='polite'. role='alert' is equivalent to aria-live='assertive'. Use live regions for form errors injected dynamically, toast notifications, chat messages, and search results that load without a page refresh.
What does aria-hidden do?
aria-hidden='true' removes an element and all its children from the accessibility tree — screen readers skip it entirely. Use it for decorative icons, repeated or redundant content, and visual elements that would create noise (like duplicate labels). Never apply aria-hidden to focusable elements — keyboard users can still reach them but screen readers won't announce anything, creating a confusing silent tab stop.
Scan for ARIA Errors on Your Website
RatedWithAI's accessibility scanner detects broken ARIA label associations, missing roles, invalid ARIA states, and other common ARIA implementation errors. Get a free report showing exactly what needs to be fixed.