Site icon IT & Life Hacks Blog|Ideas for learning and practicing

The Complete Guide to Correct ARIA Usage: WAI-ARIA Basics and Anti-Patterns for Conveying “Reading, Operation, and State” (Practical WCAG 2.1 AA Compliance)

programming codes screengrab

Photo by Myburgh Roux on Pexels.com

The Complete Guide to Correct ARIA Usage: WAI-ARIA Basics and Anti-Patterns for Conveying “Reading, Operation, and State” (Practical WCAG 2.1 AA Compliance)

Summary (Key Points First)

  • ARIA is powerful, but when misused it can break accessibility. It is a “strong tool.” The mantra is “Native first, ARIA only where needed.”
  • What matters most is correctly conveying Name, Role, and State/Value to assistive technologies.
  • Do not try to solve everything with aria-label. Keep it aligned with visible labels, and add explanations with aria-describedby when necessary.
  • The fastest path is to learn the safe patterns for common composite UIs such as modals, tabs, menus, comboboxes, and live regions.
  • This article includes many ARIA anti-patterns that commonly cause issues in real projects, along with drop-in replacement examples.

Target Audience (Concrete): Front-end engineers, UI/UX designers, design system maintainers, QA engineers, CMS developers, accessibility specialists, and agency implementers
Accessibility Level: Targeting WCAG 2.1 AA compliance (especially 4.1.2 Name, Role, Value; 2.1.1 Keyboard; 1.3.1 Info and Relationships; 2.4.6 Headings and Labels, etc.)


1. Introduction: ARIA Is Not a “Magic Spell,” but a Language for Explanation

WAI-ARIA (ARIA) is a mechanism for supplementing UI meaning for assistive technologies such as screen readers.
For example, a button is understood as “something clickable” because the <button> element has that role built in.

In real-world work, however, we often encounter buttons built with divs for visual freedom, or complex UIs such as tabs, menus, comboboxes, and modals. In those situations, ARIA can be extremely helpful.

That said, ARIA does not automatically make things better. If you declare the wrong role or state, you send incorrect information to assistive technologies.
In this article, we will carefully organize the mindset and safe patterns needed to use ARIA correctly, minimally, and without breaking things.


2. The Absolute Golden Rule: “Native First, ARIA Only for What’s Missing”

The iron rule of ARIA can be stated strongly as follows:

Use ARIA only for what cannot be done with native HTML

2.1 Why “Native First”?

Native elements (button, a, input, select, etc.) already come with:

  • Keyboard interaction
  • Focus management
  • Built-in roles
  • States (disabled, checked, etc.)
  • Accessible name computation

These have been optimized for years by browsers and assistive technologies.
By contrast, div role="button" often becomes a button only in appearance, requiring you to manually implement Enter/Space handling, focusability, disabled behavior, and more. The room for error increases dramatically.

2.2 Some Things ARIA Cannot Fix

ARIA does not improve visual design or interaction quality itself:

  • Insufficient color contrast
  • Touch targets that are too small
  • Broken tab order
  • Overly complex language

These cannot be solved with ARIA. That is why the correct order is: fix structure and interaction first, then supplement meaning with ARIA.


3. Start Here: Getting Name, Role, and State/Value (NRV) Right

The most important information ARIA provides to assistive technologies is the basic understanding of UI, often called NRV.

  • Name: What is it called? (e.g., Search, Close, Save)
  • Role: What is it? (button, link, tab, checkbox…)
  • State/Value: What is its current state? (open/closed, selected, value percentage…)

3.1 Accessible Names: Prefer Visible Labels First

Whenever possible, create names in this order:

  1. Text inside the button (most natural)
  2. <label> with for (forms)
  3. aria-labelledby (to combine multiple elements)
  4. aria-label (last resort)

Example: Using a heading as part of a button name (aria-labelledby)

<h2 id="dlgTitle">Notification Settings</h2>
<button aria-labelledby="dlgTitle openBtn" id="openBtn">
  Open
</button>

This results in a more contextual reading such as “Notification Settings Open.”

3.2 Use aria-describedby for Explanations (Don’t Mix Them into the Name)

Keep names short and explanations separate. This reduces listening fatigue.

<label for="email">Email address (required)</label>
<input id="email" type="email" aria-describedby="emailHint">
<p id="emailHint">Example: example@example.com</p>

4. ARIA Anti-Patterns: Common Pitfalls and Safe Replacements

This section is critical, so we’ll be strict.

4.1 Overusing div role="button"

Problem: Not focusable with Tab, not operable with Space, fake disabled states, and many other issues.
Replacement: Just use <button>.

Bad:

<div role="button">Save</div>

Good:

<button type="button">Save</button>

4.2 Solving Everything with aria-label

Problem: If visible labels and spoken labels don’t match, users get confused (WCAG 2.5.3 Label in Name).
Replacement: Start with visible text, and use aria-label only when unavoidable.

4.3 Overusing aria-hidden="true" to “Hide” Things

Problem: Creates dangerous situations where content is visible but silent to screen readers.
Replacement:

  • If visually hidden: use hidden or display: none
  • If disabling background interaction in modals: use inert where supported

4.4 Unnecessary Roles (e.g., role="button" on a <button>)

Problem: Redundant and sometimes alters behavior.
Replacement: Trust native semantics.
(This reflects the principle: no ARIA is better than bad ARIA.)


5. Component-by-Component: Safe ARIA Patterns for Practice

This is the core section. Learn these common UI patterns as stable “forms.”


5.1 Icon Buttons (Search, Close, Share)

Key point: Treat the icon as decorative (alt="") and name the button itself.

<button type="button" aria-label="Close">
  <img src="close.svg" alt="">
</button>
  • Visible focus styles (:focus-visible) are also mandatory.

5.2 Disclosure (Accordions, Details)

Key point: Use button as the trigger, aria-expanded for state, and aria-controls for the target.

<button aria-expanded="false" aria-controls="faq1" id="btn1">
  Can I change the delivery date?
</button>
<div id="faq1" hidden>
  Yes, you can change it before shipment.
</div>
  • When opened, remove hidden and set aria-expanded="true".
  • Combining with heading structure (e.g., h3) reduces confusion.

5.3 Modals (Dialogs)

Required behaviors:

  • Move focus into the modal when opened
  • Trap focus inside
  • Close with Esc
  • Restore focus to the trigger on close
  • Associate the title (aria-labelledby)

Example (Basic Pattern)

<button id="open">Open settings</button>

<div role="dialog" aria-modal="true" aria-labelledby="dlgTitle" hidden id="dlg">
  <h2 id="dlgTitle">Notification Settings</h2>
  <p id="dlgDesc">Select notification types and save.</p>

  <label><input type="checkbox"> Email notifications</label>
  <label><input type="checkbox"> Push notifications</label>

  <div class="actions">
    <button type="button" id="save">Save</button>
    <button type="button" id="close">Close</button>
  </div>
</div>

Note: If you want to fully silence the background, inert is a safe option where supported.
Modals are highly error-prone, so standardizing them in a design system is extremely valuable.


5.4 Tabs

Basics:

  • role="tablist"
  • Tabs use role="tab" (usually buttons)
  • Panels use role="tabpanel"
  • Selection via aria-selected
  • Arrow key navigation (roving tabindex)
<div role="tablist" aria-label="Product Information">
  <button role="tab" id="t1" aria-controls="p1" aria-selected="true" tabindex="0">Overview</button>
  <button role="tab" id="t2" aria-controls="p2" aria-selected="false" tabindex="-1">Specs</button>
  <button role="tab" id="t3" aria-controls="p3" aria-selected="false" tabindex="-1">Reviews</button>
</div>

<section role="tabpanel" id="p1" aria-labelledby="t1">…</section>
<section role="tabpanel" id="p2" aria-labelledby="t2" hidden>…</section>
<section role="tabpanel" id="p3" aria-labelledby="t3" hidden>…</section>

Note: Tabs are for switching views within the same context. If it feels like page navigation, links are usually more appropriate.


5.5 Live Regions (Notifications: Save Complete, Search Results)

Key point: Convey results quietly. Use role="status" for success, role="alert" for errors.

<div id="status" role="status" aria-atomic="true"></div>

<script>
  function saved(){
    document.getElementById('status').textContent = 'Saved successfully.';
  }
</script>
  • aria-atomic="true" is useful when you want the whole sentence read.

5.6 Comboboxes (Search Suggestions, Autocomplete)

This is a difficult area. The implementation cost is high and ARIA misuse is common. Whenever possible, use mature UI libraries or native elements such as datalist instead of rolling your own.

If you must build one, correctly manage role="combobox", aria-expanded, aria-controls, aria-activedescendant, arrow key navigation, and announcements.
(This topic alone could fill an entire article, so fixing a single approved pattern in your design system is usually the practical approach.)


6. Text, Labels, and State Design: Don’t Confuse Users with Words

Even perfect ARIA won’t help if labels are vague. Words like “Here,” “Details,” or “Submit” lose meaning in lists of links or buttons.

6.1 Strong Labels Use “Verb + Object”

  • Bad: Details
  • Good: View order details, Change shipping address, Download receipt

6.2 Duplicate State Visually and Audibly

  • Expanded state: aria-expanded + “Open/Close” text
  • Selection state: aria-selected + visual highlight
  • Errors: aria-invalid + error text

7. Testing: Judge ARIA by “Does It Work?”, Not “Is It There?”

ARIA is declarative. The only reliable validation is actual interaction and reading output.

7.1 Five-Minute Smoke Test (ARIA-Focused)

  1. Can all primary actions be completed with Tab?
  2. Are button/link names specific when listed?
  3. Does aria-expanded track open/close state correctly?
  4. In modals, does focus stay inside and return on close?
  5. Are aria-invalid and aria-describedby correctly applied to errors?
  6. Are status/alert messages announced where needed?

7.2 Minimum Screen Reader Checks

  • Roles such as “button” or “checkbox” are correct
  • States like “selected” or “expanded” are announced
  • Labels describe purpose, not icon names

8. Bringing It into a Design System: Making ARIA a Team Standard

To connect this with a design system, ARIA should be integrated as follows.

8.1 Document the “Minimum ARIA Set” per Component

Example for Disclosure:

  • Required: aria-expanded, aria-controls
  • Behavior: must track open/close state
  • Forbidden: div role="button"

8.2 Fix One Implementation Pattern

Allowing multiple patterns leads to review hell.
Decide “Tabs use this pattern,” “Modals use this pattern,” and share the code.

8.3 Define Acceptance Criteria by Outcomes

Instead of “has a tablist,” require:

  • “Tabs can be moved with arrow keys and the selected state is announced.”

9. Value for Each Audience

  • Screen reader users: Correct names and states drastically reduce getting lost.
  • Keyboard users: Native-first design ensures natural operation.
  • Users with cognitive differences: Clear state changes prevent confusion.
  • Development teams: Fewer anti-patterns mean fewer regressions and cheaper reviews.
  • Design system operations: Specified ARIA requirements ensure consistent quality across products.

10. Accessibility Level Assessment (This Article’s Target)

  • Core support for WCAG 2.1 AA
    • 4.1.2 Name, Role, Value: Correct ARIA and exposed states
    • 2.1.1 Keyboard: Native elements, modal/tab interaction rules
    • 1.3.1 Info and Relationships: Proper structure (tabs/forms)
    • 2.4.6 Headings and Labels: Specific, aligned labels
    • 2.4.7 Focus Visible: Ensured via CSS and design systems
    • 3.3.x Input Assistance: Error association (aria-invalid, aria-describedby)

In short, this article aims to stabilize the most fragile UI areas in AA compliance through correct ARIA usage.


11. Conclusion: ARIA Is Strongest When It’s Minimal and Precise

  1. Start with native HTML. Use ARIA only where needed.
  2. Fix NRV (Name, Role, State/Value) to stabilize screen reader experiences.
  3. Avoid over-reliance on aria-label; combine visible labels with aria-describedby.
  4. Standardize safe patterns for modals, tabs, disclosures, and notifications.
  5. Avoid anti-patterns (div buttons, aria-hidden abuse, unnecessary roles).
  6. Encode specs and acceptance criteria into your design system.

ARIA is a tool for expressing kindness through accurate language.
Minimal, precise, and sustainable. May your UI become a place where no one gets lost. I’ll be happy to support you every step of the way.


References (Primary Sources)

Exit mobile version