What is ARIA
ARIA (Accessible Rich Internet Applications), also known as WAI-ARIA, is a technical specification developed by the World Wide Web Consortium (W3C) (external link). It consists of a set of special HTML attributes that developers add to code to make web content and applications more accessible to people with disabilities, especially those who rely on screen readers.
When to use ARIA
Use ARIA only when native HTML isn't enough to convey meaning or state. Use it primarily for custom widgets (like modal dialogs, tabs, etc.) built with <div> tags, dynamic content updates (using aria-live), or to provide context for non-text elements, always prioritizing built-in HTML elements like <button> or <input> first for better accessibility. ARIA bridges gaps where standard HTML lacks semantics for assistive technologies (AT).
When to use aria-label: Practical examples
The aria-label attribute (external link) provides an accessible name for elements that lack visible text labels. Use aria-label for elements without a visual label, such as navigation landmarks and SVG images. However, avoid using aria-label on elements that already have visible text labels, as this can create accessibility issues.
Why you should avoid aria-label on elements containing visible text
According to WCAG 2.2 Success Criterion 2.5.3: Label in Name (Level A) (external link), when a user interface component has a visible text label, the text seen by sighted users must be the beginning of the text heard by screen reader users (the accessible name). Using aria-label can violate this requirement because it overrides the visible text, potentially causing confusion for speech input users who try to activate elements by speaking their visible labels.
Better approach: Instead of using aria-label on elements with visible text, use aria-describedby to reference any additional context needed. This ensures the visible label is included in the accessible name while adding necessary context.
Example 1: Navigation element
When you have multiple <nav> elements on a page (for example, header and footer navigation), use aria-label to differentiate them. The screen reader will announce "Main navigation" and "Secondary navigation."
Important: Do not include the word "navigation" in the aria-label for a <nav> tag, as screen readers announce it by default, causing duplication.
<nav aria-label="Main">
...
</nav>
<nav aria-label="Secondary">
...
</nav>Multiple nav elements with aria-label CodePen example (external link)
Example 2: SVG images
For SVG images that convey meaning, use the role="img" attribute along with aria-label to provide a text alternative.
<svg xmlns="https://www.w3.org/2000/svg">
<circle role="img" cx="50" cy="50" r="40" stroke="black" fill="red" aria-label="A red circle with black border"></circle>
</svg>Accessible SVG image using aria-label CodePen example (external link)
When to use aria-labelledby: Practical examples
The aria-labelledby attribute (external link) references one or more element IDs to create an accessible name by combining their text content. This attribute is particularly useful for creating unique, descriptive labels for buttons or links that share the same visible text.
Key benefits of aria-labelledby
- Dynamic updates: When the text of a referenced element changes, the accessible name automatically updates without requiring code changes.
- Combines multiple elements: reference up to three different element IDs to create truly unique and meaningful labels.
- Screen reader shortcuts: When screen reader users navigate by element type (such as listing all links or buttons),
aria-labelledbyensures each element appears with its full combined text, making them distinguishable from one another. - Takes precedence:
aria-labelledbyoverrides all other labeling methods, includingaria-label,<label>tags, and the element's inner text.
Best practice for reference order
Always reference the element's own ID first, then add secondary reference IDs. For buttons or links in tables (such as edit, delete, view), you may need a third ID reference to make the accessible name unique, clear, and descriptive.
Example 1: Multiple buttons or links inside cards
When you have several buttons or links inside cards for example “Edit”, “Remove”, use aria-labelledby to reference both the link's own ID first and the heading or content it relates to. Reference short pieces of text only, don’t reference entire paragraphs.
Screen reader accessible and responsive cards list CodePen example (external link)
Example 2: Contact information labels
For phone numbers and email addresses, combine the link text with additional context to create descriptive labels.
Accessible email, phone, and SMS text links CodePen example (external link)
Example 3: Table action buttons
For view, edit, and delete buttons in tables, reference the button's own ID first, then additional IDs from content in other table cells. Reference short pieces of text only, combining up to three IDs (including the action element’s own ID) to create unique labels like "Edit John Smith" or "Delete Invoice 12345."
Responsive table with edit and delete button using aria-labelledby CodePen example (external link)
When to use aria-describedby: Practical examples
The aria-describedby attribute (external link) references element IDs to provide additional descriptive information that supports the accessible name.
Unlike aria-labelledby, the text from aria-describedby does not appear in screen reader shortcut lists for links and buttons.
When to use aria-describedby
Use aria-describedby to reference:
- Form helper text or hint text that provides form input instructions (WCAG 2.1 Success Criterion 3.3.2: Labels or Instructions)
- Inline error messages in form validation (WCAG 2.1 Success Criterion 3.3.1: Error Identification)
- Additional instructions, such as keyboard shortcuts for keyboard-only users
- Screen reader-only text that provides context
Example 1: Form helper text
Reference helper text that explains input requirements, such as password formatting rules or date format expectations.
Accessible hint text CodePen example (external link)
Example 2: Inline form error messages
When a form field contains an error, use aria-describedby to associate the error message with the input field, ensuring screen reader users hear the error description.
External link identification techniques
External links navigate users away from your website to third-party sites. It's important to inform users when a link will take them to an external site.
Technique 1: Using aria-describedby with an icon
Add a special icon like a right upward pointing arrow (ASCII character #8599)
to visually indicate external links and use aria-describedby to reference hidden text that explains the link behavior.
<a href="https://example.com" aria-describedby="externalWebsite">
Example Site <span class="external-icon" aria-hidden="true">↗</span>
</a>
<span id="externalWebsite" tabindex="-1" aria-hidden="true" class="visually-hidden">
external website
</span>The hidden <span> element uses:
tabindex="-1"to prevent keyboard and screen reader navigation to it out of contextaria-hidden="true"so it won't be read except when referenced viaaria-describedby- The
.visually-hiddenCSS class for visual hiding
Technique 2: Including text in the visible label
Add descriptive text directly to the link's visible label to inform all users about the link's behavior.
<a href="https://www.w3.org/WAI/WCAG21/Understanding/language-of-parts.html">
HTML Language Code Reference (external link)
</a>Recommended text descriptions
- "external link" – Use when the link navigates to another website that may or may not be accessible
- "opens new tab" – Use when the link stays on your website but opens in a new tab (
target="_blank") - "opens zoom meeting" – Use when activating link launches another application
Avoid: "opens new window" is outdated since modern browsers rarely open new windows unless specifically programmed with JavaScript.
When to use visually hidden text: Practical examples
Visually hidden text provides content that is accessible to screen readers but not visible on screen. This technique is useful when special symbols like slashes or dashes are used, which screen readers may not read or may read incorrectly.
Best practice: Combine visually hidden text with aria-hidden="true" on the symbols themselves. Many screen readers have symbols like slashes and dashes turned off by default, so these symbols won't be announced unless users change their settings. Hiding symbols from screen readers while providing descriptive text ensures consistent, clear communication for all users.
Common use cases
- Date ranges: "Mo - Fri" becomes "Monday through Friday"
- Star ratings: "3/5" becomes "3 out of 5"
- Date formats: "3/1/2025 - 3/10/2025" includes "through" or "to" for clarity
Example code
html
<!-- Day range -->
<p>Mo <span aria-hidden=”true”>-</span> <span class="hidden">through</span> Fri</p>
<!-- Star rating -->
<p>3<span aria-hidden=”true”>/</span><span class="hidden"> out of </span>5</p>CSS for visually hidden class
.hidden {
position: absolute;
left: -10000px;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
}Important: Do not use display: none; or visibility: hidden; as these properties hide content from screen readers as well.
Using aria-current="page": Practical examples
The aria-current attribute (external link) indicates the current item within a set of related elements. The value "page" specifically identifies the current page within a navigation structure.
Example 1: Main navigation
In main navigation menus, apply aria-current="page" to the link representing the current page, helping users identify where they are in the site structure.
Accessible page template CodePen example (external link)
Example 2: Breadcrumb navigation
In breadcrumb trails, use aria-current="page" on the link representing the current page to help screen reader users understand their location in the site hierarchy.
Accessible breadcrumb example (external link)
Example 3: Pagination navigation
When using pagination for example below a table, use aria-current="page" on the link representing the current page to help screen reader users understand their location in the site hierarchy.
Using aria-expanded: Practical examples
The aria-expanded attribute (external link) indicates whether a collapsible element is currently expanded (true) or collapsed (false). This attribute is essential for expand/collapse controls, accordions, and dropdown menus.
When to use aria-expanded
Use aria-expanded on buttons or links that control the visibility of other content. JavaScript should toggle the value between true and false when the control is activated.
Example implementations
- Responsive navigation menus with expand/collapse functionality
- Accordion components
- Dropdown controls
Using aria-owns: Practical examples
The aria-owns attribute (external link) identifies relationships between elements when the DOM structure doesn't reflect their true relationship. This attribute is useful when an element controls or owns another element that isn't its DOM child.
When to use aria-owns
Use aria-owns in expand/collapse components and for dialog modals where the controlling button and the controlled content are not parent-child in the DOM structure but need to be understood as related by assistive technologies (AT).
Expand/collapse implementation examples
The following examples demonstrate three common implementations of expand/collapse patterns using ARIA attributes:
- Responsive navigation menu with expand/collapse
This example shows a mobile-friendly navigation menu that uses a menu button to expand and collapse navigation itemd. Accessible responsive main nav using menu button and expand/collapse CodePen example (external link) - Expand/collapse element
A basic expand/collapse pattern useful for showing and hiding content sections, often used in FAQ pages or content accordions.
Accessible expand collapse CodePen example (external link) - Simple dropdown with expand/collapse
A dropdown control pattern commonly used for filters, settings, or secondary navigation options.
Accessible dropdown control CodePen example (external link)
Dialog modals: Implementation and best practices
Dialog modals (also known as pop-ups, modal windows, dialog boxes, alerts, lightboxes, overlays, or simply modals) temporarily overlay the main page content to focus user attention on a specific task or message.
Essential ARIA attributes and behaviors
role="dialog": Apply this role to the container element that holds the modal content.aria-controls="modal-container-id": Add this attribute to the button that triggers the modal, informing assistive technologies (AT) which dialog container it controls.aria-haspopup="true": Add this attribute to the button that triggers the modal, informing assistive technologies (AT) that activating the button will open a dialog.
Focus management:
When the modal first opens, focus must move to either:
- The close button, or
- The first focusable element inside the modal
Keyboard functionality:
- Tab key should cycle through focusable elements within the modal only (focus trap)
- Focus should not reach elements behind the modal while it's open
- Escape key should close the modal and return focus to the trigger button
- If a modal was opened without using a trigger button on page load, when the modal is closed the focus should be moved to the first focusable element on the page
Example implementations
- Standard modal dialog: Accessible modal dialog CodePen example (external link)
- Navigation menu as modal: Accessible responsive main nav using a menu button and a dialog modal CodePen example (external link)
ARIA for status messages and live regions
ARIA provides several attributes and roles for announcing dynamic content changes to screen reader users, ensuring they stay informed about status updates, alerts, and other real-time information.
Using role="status"
The role="status" (external link) creates a live region for status messages that are informative but not urgent.
This role is equivalent to aria-live="polite", meaning screen readers will announce the message when they finish their current announcement.
Common use cases:
- Loading indicators with progress messages
- Search results count updates
- Same page form submission confirmations
Status message and spinner using aria-live="polite" CodePen example (external link)
Using role="alert"
The role="alert" (external link) creates a live region for important, time-sensitive messages that require immediate attention.
This role is equivalent to aria-live="assertive", meaning screen readers will interrupt their current announcement to read the alert.
Common use cases:
- Success messages after form submission that loads on a new page
- Error notifications that require immediate action
- System alerts and warnings
Important timing consideration: When dynamically inserting alert messages, allow a brief delay (such as 100-200ms using the setTimeout JavaScript function) to ensure screen readers register the new content.
Example implementations
- Accessible success message using role="alert" and setTimeout function CodePen example (external link)
- Accessible success message using role="alert" and aria-atomic="true" CodePen example (external link)
Using aria-live
The aria-live attribute (external link) explicitly defines how screen readers should handle updates to live regions. This attribute accepts three values:
aria-live="polite"– Screen readers announce updates when they finish their current announcement. Use for non-urgent updates like status messages, search results, or progress indicators.aria-live="assertive"– Screen readers immediately interrupt to announce updates. Use sparingly for critical alerts that require immediate attention, such as error messages or warnings.aria-live="off"– Turns off live region announcements. Use when you need to temporarily disable announcements or for content that shouldn't be announced automatically. Use it for elements that are regularly updated that users will intentionally interact with or check, such as live sports scores, stock tickers, or chat message windows.
Additional roles for live regions
For specialized use cases, ARIA provides other live region roles including timer (external link), log (external link), and marquee (external link).
Form-specific ARIA attributes
The following ARIA attributes enhance form accessibility by providing additional context and state information to assistive technologies (AT). For comprehensive guidance on creating accessible forms, review Creating accessible HTML forms for websites and applications for a detailed implementation example.
Using aria-labelledby on the form element
Use the aria-labelledby attribute (external link) on the <form> element to reference a heading that describes the form's purpose. This creates a clear relationship between the form and its title.
<h2 id="contact-heading">Contact us</h2>
<form aria-labelledby="contact-heading">
<!-- form fields -->
</form>Using aria-describedby for helper text and error messages
Use the aria-describedby attribute (external link) to associate form fields with:
- Helper text or hint text that provides input field instructions or formatting requirements
- Inline error messages that explain validation failures
Best practice: helper and hint text should always be located either directly above or below the associated input field to meet the WCAG success criterion 3.3.2 Labels or Instructions requirement.
Important: always include helper or hint text for formatting instructions. Relying only on error messages to provide instructions will fail the WCAG success criterion 3.3.2 Labels or Instructions. Also, reference the error message ID before the helper text ID in the aria-describedby so that the error message gets announced first. The error message container should always be loaded in your page HTML, even if it's empty, so that automated accessibility testing tools won’t throw any missing ID errors.
<!-- Helper text example -->
<label for="password">Password</label>
<div id="password-hint">Must be at least 8 characters with one number</div>
<input type="password" id="password" name="password" aria-describedby="password-hint">
<!-- Error message example -->
<label for="username">Username</label>
<input type="text" id="username" name="username" aria-invalid="true" aria-describedby="username-error">
<span id="username-error" class="error">Username must be at least 3 characters long</span>Don't use role="alert" for error messages
Don't use role="alert" for inline form validation error messages. The alert role causes screen readers to immediately announce the error, which can be disruptive and confusing during form completion. Instead, use aria-describedby to associate error messages with their fields, and use aria-invalid="true" to indicate the error state. The screen reader will announce the error state and message when the field receives focus.
Using aria-required for required fields
The aria-required attribute (external link) indicates that user input is required before form submission. While the HTML5 required attribute is also available, we recommend that you use aria-required="true" to have more control over form validation styles and screen reader announcement timing.
<label for="email">Email address</label>
<input type="email" id="email" name="email" aria-required="true">Best practice: To ensure screen readers announce input labels upon focus, use the for attribute on the <label> tag to reference the input's id.
Using aria-invalid for formatting errors
The aria-invalid attribute (external link) indicates that a field's current value doesn't meet validation requirements. Set aria-invalid="true" when a field contains incorrectly formatted data and change it back to aria-invalid="false" when the error has been fixed by the user.
Important: Do not use aria-invalid for empty required fields, use it only for fields with formatting errors (such as an invalid email format or phone number).
<label for="phone">Phone number</label>
<div class="hintText" id="phone-hint">Format: (555) 555-5555</div>
<input type="tel" id="phone" name="phone" aria-invalid="true" aria-describedby="phone-error phone-hint">
<span id="phone-error" class="error">Please enter a valid phone number format: (555) 555-5555</span>Success message examples
Using JavaScript to insert message text into a div container that has either role="status" or role="alert" (and is already present in the DOM) will trigger the screen reader to announce the message. The role="status" implicitly includes aria-atomic="true" and aria-live="polite", while role="alert" implicitly includes aria-atomic="true" and aria-live="assertive", which helps guarantee the entire message is announced.
When to use role status vs alert
- Use
role="status"(polite announcement) when the success message loads on the same page - Use
role="alert"(immediate announcement) when the success message loads on a new page
Best practice: to ensure users know any relevant information, success messages should include relevant info like clear next steps.
Using role="status" (polite announcement):
<div role="status">
Your message has been sent successfully. We'll respond within 24 hours.
</div>Using role="alert" (immediate announcement):
<div role="alert">
Your account has been created successfully!
</div>
Using aria-pressed: Practical examples
The aria-pressed attribute (external link) indicates the current pressed state of toggle buttons. Use this attribute for buttons that can be switched between two states (on/off, pressed/not pressed) where the button text remains constant.
HTML Example: Mute button
<button id="muteBtn" role="button" aria-pressed="false" aria-label="Mute">
<span class="icon-speaker"></span> Mute
</button>How it works:
- Initial state:
aria-pressed="false"(not pressed/unmuted) - When activated: JavaScript changes it to
aria-pressed="true" - Screen reader announcement: "Mute toggle button pressed" or "Mute toggle button not pressed"
- Key point: The text "Mute" does not change; the aria-pressed attribute handles the state
When not to use aria-pressed
Changing labels: If the button text changes with state (for example, "Play" to "Pause"), use a standard <button> or a styled <input type="checkbox">, not aria-pressed, because the label itself conveys the state.
Simple commands: For actions that don't toggle (like "Submit" or "Close"), omit aria-pressed.
Additional custom components using ARIA
The following custom components require ARIA attributes to ensure they're accessible to assistive technologies (AT). Each component implements specific ARIA patterns and keyboard interactions.
Tooltips
Use tooltips for brief, contextual hints (definitions, short instructions) to be shown on hover or focus. Accessible tooltips use the ARIA attribute role="tooltip" to ensure proper screen reader support.
Accessible tooltip CodePen example (external link)
Tabs
Use tab interfaces to organize content into panels that users can switch between. Each tab container's content can be static or dynamically loaded. Don't use tabs for content that requires a page reload. Accessible tabs require ARIA roles, states, and keyboard navigation to communicate structure and allow efficient interaction.
Additional Resources
For help including design reviews, code reviews, or additional training contact the ACCESS team using the ACCESS team’s intake form.
The following WCAG 2.2 success criteria are covered in this guide:
- WCAG 2.1 Success Criterion 2.4.4: Link Purpose (In Context) (Level A) (external link)
- WCAG 2.2 Success Criterion 2.5.3: Label in Name (Level A) (external link)
- WCAG 2.1 Success Criterion 3.3.1: Error Identification (Level A) (external link)
- WCAG 2.1 Success Criterion 3.3.2: Labels or Instructions (Level A) (external link)
- WCAG 2.1 Success Criterion 4.1.2: Name, Role, Value (Level A) (external link)