Chapter 42: WAI-ARIA Roles & Semantics

The WAI-ARIA Accordion Pattern

Building enterprise-grade, keyboard-accessible FAQ and multi-section accordions with header button bindings, aria-expanded, and aria-controls.

LEARNING OBJECTIVES
  • Understand the structural anatomy of the W3C APG Accordion pattern.
  • Correctly nest native <button> triggers inside semantic heading tags (<h3>).
  • Synchronize dynamic disclosure states using aria-expanded="true|false" and aria-controls.
  • Compare native HTML5 <details>/<summary> with custom WAI-ARIA Accordion implementations.
🎬 INTERACTIVE VISUAL PIPELINE Core Architecture Simulation
🌐
1. Input
Directives & Tags
⚙️
2. Parse
Tokenizer & AST
🌳
3. Layout
Box Model & Flow
🎨
4. Render
GPU Paint & Composite
PHASE 1: INPUT & DIRECTIVES
Browser receives declarative markup stream, parsing tag tokens and initializing component state.

📖 The Mental Model & Story (Intuitive Foundation)

Imagine an accordion musical instrument. When compressed, its pleated bellows take up very little physical space. When the musician pulls the handles apart, the bellows expand, allowing air to flow through the internal reeds and create rich sound.

In user interface design, an Accordion operates on the exact same principle of spatial efficiency. When you have a massive FAQ page containing 25 extensive answers, presenting all 25 answers expanded simultaneously creates a 10,000-pixel vertical wall of text.

By grouping related content into collapsible panels, users can quickly scan the compressed headers to find what they need, and selectively expand only the specific answer they wish to read.

Without ARIA, custom accordions built with <div> click handlers leave screen reader users completely unaware of whether a section is open, closed, or what content appeared when clicked.

The WAI-ARIA Accordion Pattern provides clear audio feedback: "Frequently Asked Questions. Heading level 3, button: How do I reset my password? collapsed. Press Space to expand."


Technical Deep Dive & Specifications

The Accordion Structural Anatomy

+-----------------------------------------------------------------------------+
|                          ACCORDION SECTION ANATOMY                          |
+-----------------------------------------------------------------------------+
|                                                                             |
|  <h3>                                                                       |
|    <button                                                                  |
|      type="button"                                                          |
|      id="acc-header-1"                                                      |
|      aria-expanded="false"                                                  |
|      aria-controls="acc-panel-1">                                           |
|      What is your refund policy?                                            |
|    </button>                                                                |
|  </h3>                                                                      |
|                                                                             |
|  <div                                                                       |
|    role="region"                                                            |
|    id="acc-panel-1"                                                         |
|    aria-labelledby="acc-header-1"                                           |
|    hidden>                                                                  |
|    <p>We offer a 30-day money-back guarantee with zero hassle...</p>        |
|  </div>                                                                     |
|                                                                             |
+-----------------------------------------------------------------------------+

The 3 Core Requirements of WAI-ARIA Accordions

  1. Heading Containment (<h3><button>...</button></h3>):

    • The accordion trigger must be a native <button> nested inside a semantic heading (<h2> through <h6>).
    • This ensures screen reader users can navigate the page using both heading shortcuts (H key) and form/button shortcuts.
  2. State & Association Attributes:

    • aria-expanded="true|false" on the <button>: Conveys whether the controlled panel is visible.
    • aria-controls="panel-id" on the <button>: Identifies which panel container is toggled.
    • aria-labelledby="header-btn-id" on the panel: Links the panel back to its header.
    • role="region" on the panel: Exposes the expanded panel as a distinct landmark region once open.
  3. Panel Visibility Management:

    • Inactive panels must be hidden using the HTML5 hidden attribute or CSS display: none.
    • Collapsed content must never be accessible in the keyboard tab order while hidden.

Keyboard Interaction Contract

Keystroke Behavior
Enter or Space Toggles the expanded/collapsed state of the focused accordion header button.
Tab Moves focus to the next focusable element (either the next accordion header or an interactive link/button inside an open panel).
Shift + Tab Moves focus to the previous focusable element.
ArrowDown (Optional APG Enhancement) Moves focus to the next accordion header button.
ArrowUp (Optional APG Enhancement) Moves focus to the previous accordion header button.
Home / End (Optional APG) Moves focus to the first or last accordion header button.

Native HTML5 <details> vs. Custom ARIA Accordion

Modern HTML provides the native <details> and <summary> disclosure element:

<!-- Native HTML5 Disclosure Element -->
<details>
  <summary>What is your refund policy?</summary>
  <p>We offer a 30-day money-back guarantee.</p>
</details>
Dimension Native <details> / <summary> Custom WAI-ARIA Accordion
JavaScript Required Zero JS (Browser handles toggling natively) ✅ Requires JS for state toggling
Heading Hierarchy Requires nesting <h3><summary> (some browsers have styling quirks) Full semantic heading integration (<h3><button>)
CSS Animation Support Limited (improving with modern CSS interpolate-size) Full control over JavaScript height animations
Exclusive Accordion Grouping Requires name="group-name" attribute (HTML 2024+) Custom JS logic for single-open vs multi-open behavior

SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
HTML STARSHIP CODE TERMINAL example.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...

💻 Interactive Code Playground

Starter Code: Production-Grade Accessible FAQ Accordion

Line-by-Line Code Breakdown

  • Lines 49–57 (<h2><button ...>): Semantic <h2> preserves the document outline; the inner <button> provides native focusability, keyboard triggers (Space/Enter), and ARIA bindings.
  • Line 52 (aria-expanded="true"): Informs assistive technology that the first item is open by default.
  • Line 53 (aria-controls="acc-panel-1"): Explicitly pairs the toggle button with the panel container.
  • Line 59 (role="region" id="acc-panel-1" aria-labelledby="acc-btn-1"): Exposes the panel as a region landmark labeled by the header button.
  • Line 55 (aria-hidden="true" on the arrow icon): Hides the visual downward arrow character so screen readers don't read "down pointing triangle" aloud.
  • Lines 108–137 (JavaScript Toggle Logic): Inverts aria-expanded and toggles the HTML5 hidden attribute synchronously on click.

Expected Browser Render Output

(Clicking any header toggles its panel and updates aria-expanded immediately).


SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
HTML STARSHIP CODE TERMINAL playground.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...
Frequently Asked Questions
─────────────────────────────────────────────────────────────
How do I invite team members to my organization?           ▲
Navigate to Settings > Organization > Members and click...
─────────────────────────────────────────────────────────────
What payment methods do you accept?                        ▼
─────────────────────────────────────────────────────────────
Can I export my analytics data?                            ▼
─────────────────────────────────────────────────────────────

🏋️ Hands-On Exercise

🎯 The Challenge: Build an Accessible Multi-Step Checkout Accordion

Build an accessible 3-step checkout accordion featuring:

  1. Step 1: Shipping Address
  2. Step 2: Delivery Options
  3. Step 3: Payment Details

Instructions:

  1. Wrap each step header in an <h3> tag containing a <button type="button">.
  2. Connect each header button to its respective panel using aria-controls and aria-expanded.
  3. Give each panel role="region" and aria-labelledby referencing its header button ID.
  4. Ensure Step 1 is expanded initially, while Steps 2 and 3 are collapsed with the hidden attribute.
  5. Write JavaScript to toggle panels on button click.

🏁 Starter Code Sandbox

SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
STARTER CODE SANDBOX exercise.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...

⚠️ Common Pitfalls

  1. Putting role="button" Directly on the Heading: Writing <h2 role="button">. This strips the <h2> level from the document outline. Always nest <button> inside <h2>.
  2. Using CSS opacity: 0 or height: 0 Without display: none or visibility: hidden: If a collapsed panel is merely visually invisible, keyboard users will still tab into the invisible inputs and links inside it. Always apply hidden or display: none when collapsed.
  3. Missing aria-controls Linkage: Forgetting aria-controls="panel-id" on the accordion button prevents assistive technologies from offering direct jumping between the header and panel.

💡 Pro Tips

  1. Exclusive Accordions: To create an accordion where opening one panel automatically closes all others, loop through all other buttons in your click handler and set aria-expanded="false" and hidden before opening the targeted panel.
  2. Deep-Linking via URL Hash: Parse window.location.hash on page load. If the hash matches an accordion panel ID, automatically expand that section and scroll it into view.

📌 Key Takeaways

  • The WAI-ARIA Accordion pattern requires nesting native <button> elements inside semantic heading tags (<h2>-<h6>).
  • aria-expanded="true|false" on the trigger button communicates the disclosure state.
  • aria-controls links the trigger button to the collapsible content panel's ID.
  • Collapsible panels must use role="region" with aria-labelledby linking back to the header button.
  • Inactive panels must be hidden using the hidden attribute or display: none to prevent keyboard focus leaks.
  • --
⭐ LEARN: HTML 🌟 ⚔️ QUIZ BATTLE ARENA // ACTIVE
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 1 / 3

Why must the interactive toggle of an accordion item be placed inside a heading tag (e.g. <h3><button>...</button></h3>) rather than replacing the heading tag with a button?

Question 1 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 2 / 3

Which attribute must be toggled on the accordion trigger button when its panel is opened or closed?

Question 2 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 3 / 3

Why is applying display: none or the hidden attribute required when collapsing an accordion panel?

Question 3 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP