Compare official W3C ARIA Authoring Practices Guide (APG) custom patterns directly with native HTML5 semantic equivalents.
Test live interactive widgets, explore keyboard accessibility matrices, inspect implementation effort, and operationalize the First Rule of ARIA.
30Patterns Analyzed
14Native Preferred
11Hybrid Enhancement
5ARIA Required
📜
The First Rule of ARIA
"If you can use a native HTML element or attribute with the semantics and behavior you require already built in, then do so."
— W3C ARIA Authoring Practices Guide & Using ARIA in HTML
Native Preferred:HTML provides a built-in element (e.g. <dialog>, <details>, <meter>, <input type="range">). Use native HTML first.
Hybrid Enhancement:Semantic HTML structure combined with targeted ARIA (e.g. <nav> + aria-current="page", Popover API, indeterminate checkboxes).
ARIA Required:No native HTML element exists yet (e.g. tabs, treeview, toolbar). The APG pattern is required for full accessibility.
A vertically stacked set of interactive headings that each reveal a section of content. Modern HTML natively supports exclusive accordions with name="group" without JavaScript.
First Rule Analysis:
Under the First Rule of ARIA ("No ARIA is better than bad ARIA"), native <details> with <summary> is vastly superior for standard document and content disclosure. Modern browsers support exclusive accordions natively using the name attribute on multiple <details> tags (opening one closes the others). The APG ARIA pattern requires custom buttons, aria-expanded, aria-controls, role="region", and custom JavaScript keyboard event handlers.
/* Styling ARIA Accordion via state attributes */
.accordion-trigger[aria-expanded="true"] .acc-icon {
transform: rotate(180deg);
}
.accordion-panel[hidden] {
display: none;
}
💡 Pro Styling Tips:
Use summary::-webkit-details-marker { display: none; } and list-style: none on summary to remove default arrows across all engines.
Target details[open] summary to change background or rotate custom indicator icons.
Modern Semantic HTML5 Markup
<!-- Modern Semantic HTML5 Exclusive Accordion (0 JS needed!) -->
<details name="faq-group">
<summary>Billing Information</summary>
<div class="panel-content">
<p>Billing address and payment details go here.</p>
</div>
</details>
<details name="faq-group">
<summary>Shipping Information</summary>
<div class="panel-content">
<p>Shipping addresses and carrier options.</p>
</div>
</details>
/* Note:
Using name="faq-group" makes details elements exclusive: expanding one automatically collapses all others in the same group natively!
*/
A modal dialog overlays the main view and requires user interaction before returning. The native HTML <dialog> provides top-layer rendering, native focus trapping, Esc closing, and automatic backdrop styling.
First Rule Analysis:
Implementing an accessible modal dialog with ARIA from scratch is notoriously error-prone: you must manage a backdrop div, trap keyboard focus within the dialog, handle the Esc key, mark all background DOM nodes as inert or aria-hidden="true", and restore focus to the trigger on close. Native <dialog>.showModal() does ALL of this in the browser engine natively.
Semantic Target:<dialog> + showModal()
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
Confirm Deletion
Are you sure you want to permanently delete this item?
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern Extreme Effort (~70-110 lines of complex JS + HTML)
Focus trap leaks and missing background inerting are among the most common web accessibility failures.
Wiring & Implementation Requirements:
Container element with role="dialog", aria-modal="true", and aria-labelledby="title-id"
Fixed viewport backdrop <div> element
JavaScript focus trap: intercepting Tab/Shift+Tab to keep focus within dialog focusable nodes
Marking all page siblings with inert or aria-hidden="true" while modal is open
JavaScript keydown listener for Escape key to close modal
Tracking opener button in document.activeElement and restoring focus upon close
Keyboard Functionality:
Tab / Shift+Tab: Trapped within dialog, cycling between first and last focusable element
Escape: Closes dialog and returns focus to opener button
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Announces "dialog modal, Confirm Deletion". Assistive tech virtual reading cursor must be confined to dialog content.
🟢 Semantic HTML Equivalent Low (1-2 lines JS) (~5 lines of HTML + 1 line JS (dialog.showModal()))
Browser Top Layer handles z-index, backdrop, focus containment, and inertness natively.
Wiring & Implementation Requirements:
Native <dialog> element in HTML
Invoked via dialog.showModal()
Native ::backdrop pseudo-element for background dimming
Optional <form method="dialog"> to close modal natively on button click without JS
Keyboard Functionality:
Tab / Shift+Tab: Automatically trapped inside modal by browser engine
Escape: Natively fires cancel event, closes dialog, and restores focus to invoking element
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Announces native dialog role, title, and isolates reading order to the dialog natively.
⚠️
Real-World Limitations of Native Semantic HTML (Dialog (Modal)):
Calling dialog.show() creates a non-modal dialog without focus trap or backdrop; dialog.showModal() must be used for modals.
Animating entry and exit transitions requires modern CSS (@starting-style and transition-behavior: allow-discrete).
Positioning relative to triggering element as a flyout requires CSS Anchor Positioning or manual offset calculation.
A toggle control representing a binary on/off state. Standard HTML checkbox supports role="switch" for exact AT announcement while preserving native form submission and keyboard interaction.
First Rule Analysis:
Developers often create custom <div> or <button> switches with ARIA, requiring manual click, spacebar, and enter handlers, plus custom state tracking. Using a native <input type="checkbox" role="switch"> leverages native checkbox form submission, native keyboard behavior, and native assistive technology support while announcing itself as a switch.
Use appearance: none directly on the input[type="checkbox"][role="switch"] to avoid extra span wrapper markup while keeping full focus visibility intact.
Modern Semantic HTML5 Markup
<!-- Semantic HTML Checkbox with switch role -->
<label class="semantic-switch">
<input type="checkbox" role="switch" name="notifications">
<span class="switch-slider" aria-hidden="true"></span>
<span>Email Notifications</span>
</label>
/* Note:
Fully keyboard accessible, participates in HTML form validation and submission, and works with JavaScript disabled.
*/
A user input where the user sets a value from a given range. Native <input type="range"> provides full keyboard, mouse, touch, and screen reader support without JavaScript.
First Rule Analysis:
The APG ARIA slider requires building custom track and thumb markup, managing aria-valuenow, aria-valuemin, aria-valuemax, tracking mouse dragging, touch movements, and listening for ArrowLeft, ArrowRight, ArrowUp, ArrowDown, PageUp, PageDown, Home, and End keys. Native <input type="range"> provides all of this out of the box with zero JavaScript.
Semantic Target:<input type="range">
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
Use ← → Arrow keys or Home/End
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
Native keyboard, mouse, touch & form integration
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern High Effort (~80-120 lines of JS + math + CSS)
Requires touch, mouse, pointer, and keyboard coordinate math and bounding box calculations.
Keydown listener for ArrowLeft, ArrowRight, ArrowUp, ArrowDown, PageUp, PageDown, Home, End
Does not participate in HTML form submit without hidden input
Keyboard Functionality:
Arrow Left / Down: Decrements value by step
Arrow Right / Up: Increments value by step
Page Up / Down: Increments / decrements by large step (e.g. 10)
Home / End: Jumps to minimum / maximum values
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Announces "slider, Volume, 50%, min 0, max 100". Updates on every step.
🟢 Semantic HTML Equivalent Minimal (0 JS) (~2 lines of HTML + CSS)
Complete accessibility, keyboard, touch swipe, and mouse drag built into the browser engine.
Wiring & Implementation Requirements:
<input type="range" min="0" max="100" value="50">
Built-in <output> element for live visual value display
0 lines of JavaScript needed for slider operation
Keyboard Functionality:
Natively supports all arrow keys, PageUp, PageDown, Home, and End without a single line of JS.
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Natively announces range slider, current value, min, max, and orientation.
⚠️
Real-World Limitations of Native Semantic HTML (Slider):
Cross-browser thumb and track styling requires two separate vendor prefixes (::-webkit-slider-thumb and ::-moz-range-thumb).
Dual-fill track styling (highlighting the completed portion of the track) is not natively standardized and requires CSS linear-gradient or accent-color.
A graphical display of a numeric value within a known range, such as disk usage or battery level. The native HTML <meter> element includes semantic understanding of optimum, low, and high thresholds.
First Rule Analysis:
The native <meter> element communicates scalar measurement and gauge semantics directly to assistive technologies. It also provides built-in attributes for min, max, low, high, and optimum, allowing browsers and user agents to convey whether a gauge is in a favorable or alert status. The ARIA role="meter" requires custom styling, manual aria-valuenow updates, and cannot natively represent the optimum range concept.
Semantic Target:<meter>
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
Storage Usage:72%
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
72%
72%
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern Medium Effort (~20 lines of HTML, CSS & JS)
Must manually compute percentages, fill widths, and color thresholds.
The primary interactive control for triggering actions. The classic demonstration of the First Rule of ARIA: a <div> with role="button" requires extensive custom JavaScript to replicate native <button>.
First Rule Analysis:
A native <button> element comes with automatic keyboard activation (both Space and Enter fire click), native focusability, native disabled state (which prevents click and keyboard events), form integration (type="submit", type="reset"), and standard accessibility API mapping. An ARIA fake button (<div role="button" tabindex="0">) requires manual keydown listeners for Space and Enter, custom disabled management, and often fails in screen reader virtual cursor modes.
Semantic Target:<button type="button">
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
Custom <div role="button">
Activated: 0 times
Requires manual Space & Enter keydown JS
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
Activated: 0 times
Native Space & Enter click, disabled state, form submit
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern High Effort (~30 lines of JS + CSS to duplicate native button)
Common source of bugs where Space key causes page scroll or disabled buttons still trigger.
Wiring & Implementation Requirements:
<div role="button" tabindex="0">
Keydown listener for Enter to invoke action
Keydown listener for Space to call e.preventDefault() (prevent page scroll) and invoke action on keyup
Manual :focus-visible styling
Manual disabled state management (aria-disabled="true" and tabindex="-1")
Does NOT submit forms without manual form submission JS
Always specify type="button" on non-submitting buttons to prevent accidental form submissions!
Modern Semantic HTML5 Markup
<!-- Semantic HTML Button -->
<button type="button" class="btn-primary" onclick="doAction()">
Save Changes
</button>
/* Note:
Requires 0 lines of helper code. Fully accessible, keyboard responsive, and form-aware out of the box.
*/
W3C APG ARIA Pattern Markup & JavaScript
<!-- W3C APG ARIA Div Button -->
<div role="button" tabindex="0" id="apg-btn" class="custom-btn">
Save Changes
</div>
// --- JavaScript Implementation ---
// Re-inventing what <button> does natively:
const btn = document.getElementById('apg-btn');
btn.addEventListener('keydown', (e) => {
if (e.key === 'Enter') doAction();
else if (e.key === ' ') {
e.preventDefault(); // Stop spacebar from scrolling page!
doAction();
}
});
Key / Trigger
W3C APG ARIA Behavior
Semantic HTML5 Behavior
Enter
Must be caught in JS keydown to invoke the button action.
Natively fires the click event on <button>.
Space
Must be caught in JS keydown, e.preventDefault() called to prevent page scroll, and action invoked on keyup.
Natively triggers button on keyup; page does not scroll.
An interactive hyperlink that navigates to a new resource or location. Native <a> elements provide essential browser features that fake ARIA links cannot replicate.
First Rule Analysis:
Using <span role="link" tabindex="0"> breaks standard web browser functionality: users cannot middle-click or right-click to "Open link in new tab", "Copy link address", or bookmark the URL. Search engine spiders cannot crawl fake links. Native <a href="..."> provides full browser navigation, context menus, and accessibility natively.
A set of checkable buttons where no more than one button can be checked simultaneously. Native radio buttons provide single tab-stop roving focus and arrow navigation natively.
First Rule Analysis:
The APG ARIA radio group pattern requires manually implementing roving tabindex (managing tabindex="0" on the selected radio and tabindex="-1" on all others), listening for ArrowUp, ArrowDown, ArrowLeft, ArrowRight, and updating aria-checked. Native <input type="radio" name="..."> grouped by a <fieldset> with <legend> provides this entire behavior natively with zero JavaScript.
A control that allows the user to toggle between checked, unchecked, or partially checked (mixed/indeterminate) states. Native checkbox handles the mixed state via the DOM indeterminate property.
First Rule Analysis:
While creating a custom checkbox (<div role="checkbox">) requires writing custom Space key listeners and focus styling, the native <input type="checkbox"> handles focus, toggling, and form submission natively. For parent "select all" checkboxes that need a mixed state, setting the DOM property checkbox.indeterminate = true provides native screen reader mixed state announcements without abandoning native checkbox semantics.
Real-World Limitations of Native Semantic HTML (Checkbox (Tri-State / Mixed)):
The indeterminate state CANNOT be set via HTML markup alone (e.g. there is no indeterminate HTML attribute); it MUST be set via JavaScript property: input.indeterminate = true.
A simple button that controls the visibility of an associated section of content. Modern HTML <details> and <summary> provide this natively with zero JavaScript.
First Rule Analysis:
The disclosure pattern is one of the most common web interactions. Before HTML5 <details>, developers used <button aria-expanded="false" aria-controls="content">. Native <details> provides complete keyboard accessibility, automatic aria-expanded state handling, built-in search-on-page text matching (browsers automatically expand details when searching with Ctrl+F), and zero JavaScript overhead.
Semantic Target:<details> + <summary>
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
Disclosed content revealed via aria-expanded and hidden attribute.
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
Show Details (Semantic <details>)
Disclosed content revealed natively with built-in browser Find (Ctrl+F) expansion.
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern Medium Effort (~20 lines of HTML + JS)
Requires synchronizing aria-expanded attribute with panel hidden state.
button[aria-expanded="true"] + div { display: block; }
💡 Pro Styling Tips:
Details contents automatically expand when users search with browser Find (Ctrl+F)!
Modern Semantic HTML5 Markup
<!-- Semantic HTML Details Element -->
<details>
<summary>What is WCAG 3.0?</summary>
<p>WCAG 3.0 is the upcoming draft standard for web content accessibility guidelines.</p>
</details>
/* Note:
Natively accessible, expands automatically when users use browser Find (Ctrl+F), and requires 0 lines of JavaScript.
*/
W3C APG ARIA Pattern Markup & JavaScript
<!-- W3C APG ARIA Disclosure Button -->
<button type="button" aria-expanded="false" aria-controls="faq-answer" id="faq-btn">
What is WCAG 3.0?
</button>
<div id="faq-answer" hidden>
<p>WCAG 3.0 is the upcoming draft standard for web content accessibility guidelines.</p>
</div>
// --- JavaScript Implementation ---
const btn = document.getElementById('faq-btn');
const ans = document.getElementById('faq-answer');
btn.addEventListener('click', () => {
const exp = btn.getAttribute('aria-expanded') === 'true';
btn.setAttribute('aria-expanded', String(!exp));
ans.hidden = exp;
});
Key / Trigger
W3C APG ARIA Behavior
Semantic HTML5 Behavior
Enter / Space
Toggles aria-expanded and panel visibility via JS.
A composite widget combining a single-line textbox with an associated popup listbox. Native <datalist> provides zero-JS autocomplete, while APG Combobox is needed for rich custom dropdowns.
First Rule Analysis:
For standard text suggestion and search autocomplete, the native HTML <datalist> element paired with an <input list="..."> provides built-in keyboard navigation, native OS suggestions, and screen reader announcements with zero JavaScript. The APG Combobox pattern is only warranted when dropdown options require rich HTML markup (avatars, subheadings, badges) or multi-select chip tags.
Semantic Target:<input list="..."> + <datalist>
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
Astro
React
Vue
Svelte
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
Native <datalist> autocomplete with 0 JavaScript
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern Extreme Effort (~120-180 lines of JS + HTML)
When simple string autocomplete is needed, use <datalist>. Switch to the APG Combobox pattern ONLY when options require rich media or multi-column layouts.
Modern Semantic HTML5 Markup
<!-- Semantic HTML Autocomplete with datalist -->
<label for="std-search">Search standards:</label>
<input type="text" id="std-search" list="standards-list" placeholder="Search standards...">
<datalist id="standards-list">
<option value="WCAG 2.2">
<option value="WCAG 3.0">
<option value="Section 508">
<option value="EN 301 549">
</datalist>
/* Note:
Supported in all modern browsers without any script. Provides native fuzzy matching and assistive technology integration.
*/
A button that opens a flyout menu. The APG Menu pattern is designed for desktop-style application command actions; for site navigation, the modern HTML Popover API is preferred.
First Rule Analysis:
One of the most widespread accessibility anti-patterns on the web is using ARIA role="menu" and role="menuitem" for site navigation links. In ARIA, a menu is an application menu (like File/Edit in a desktop app) where Tab exits the menu and Arrow keys navigate items. When applied to website dropdowns, screen reader users expect arrow navigation and cannot tab through links. Modern HTML provides the Popover API (popover, popovertarget) which gives native top-layer flyout and light-dismiss without ruining link semantics.
Semantic Target:<button popovertarget="..."> + Popover API
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
📄 Export Audit (PDF)
📋 Copy JSON Results
🗑️ Clear Findings
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
Native Top Layer, light-dismiss & Esc key support
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern High Effort (~50-70 lines of JS + CSS)
Frequently misimplemented on web navigation links where Tab navigation is broken.
Use the Popover API for flyouts and dropdowns that contain navigation links, and reserve ARIA role="menu" only for desktop-like application action palettes.
Modern Semantic HTML5 Markup
<!-- Modern Semantic HTML Popover API -->
<button type="button" popovertarget="nav-menu">
Actions ▼
</button>
<div id="nav-menu" popover class="popover-card">
<nav aria-label="Action options">
<a href="/export">Export PDF</a>
<a href="/duplicate">Duplicate</a>
<button type="button" class="btn-danger">Delete</button>
</nav>
</div>
/* Note:
Native Popover API renders in the browser Top Layer, features light-dismiss (clicking outside or pressing Esc closes it), and preserves standard Tab order.
*/
A set of layered panels where only one panel is displayed at a time. Because HTML currently lacks a native <tabs> element, the APG Tabs pattern remains the required accessible pattern.
First Rule Analysis:
Unlike dialogs, accordions, and sliders, HTML does not have a native <tabs> or <tabpanel> element (although WHATWG and OpenUI have active proposals). Therefore, implementing tabbed interfaces requires following the W3C APG Tabs pattern: role="tablist", role="tab", role="tabpanel", aria-selected="true/false", and roving tabindex with ArrowLeft/ArrowRight navigation. Some developers attempt hacks using radio buttons or details, but only the APG ARIA pattern communicates true tabbed semantics to screen readers.
Semantic Target:No native <tabs> element exists in HTML
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
Run axe-core and Lighthouse against static DOM nodes.
Verify Tab, Shift+Tab, and roving arrow key focus visibility.
Audit with NVDA, JAWS, or VoiceOver for virtual reading order.
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
⚠️
HTML Specification Notice:
No native <tabs> element exists in HTML yet. The W3C APG ARIA Tabs pattern shown on the left is the required standard for accessible tabbed interfaces.
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern High Effort (~50-70 lines of JS + HTML)
Normative standard required because HTML does not have a native <tabs> element.
Always keep tabpanel focusable (tabindex="0") if it contains no focusable interactive children, so keyboard-only users can scroll long content.
Modern Semantic HTML5 Markup
<!-- What HTML Offers Today: Multi-page navigation or Details group -->
<!-- Notice: HTML does NOT have a native <tabs> element! -->
<div class="callout-note">
<strong>Spec Status:</strong> WHATWG & OpenUI have active proposals for <tabs>.
Until standardized, the W3C APG ARIA Tabs pattern above is the normative industry standard.
</div>
/* Note:
Always ensure your tablist is treated as a single tab stop, with arrow keys switching tabs, and Tab jumping directly into the tabpanel.
*/
A tabular presentation of data. Native HTML <table> provides built-in screen reader navigation commands; ARIA role="grid" is reserved for interactive spreadsheet applications.
First Rule Analysis:
Native HTML <table> with <th> scope="col/row" and <caption> gives screen reader users built-in matrix reading shortcuts (e.g. Ctrl+Alt+Arrows in JAWS/NVDA, VO+Arrows in VoiceOver). Replacing tables with <div role="table"> is unnecessary work. Furthermore, developers often misuse role="grid" when they simply have a data table: role="grid" tells assistive technologies to disable standard table navigation in favor of arrow-key cell traversal, which should only be used for interactive widgets like spreadsheets or calendars.
A stepper input for selecting a numeric value from a defined range. Native <input type="number"> provides native stepper controls, mobile numeric keyboards, and keyboard navigation.
First Rule Analysis:
The APG ARIA spinbutton requires a <div> with role="spinbutton", aria-valuenow, aria-valuemin, aria-valuemax, plus increment and decrement buttons and custom keydown listeners for ArrowUp, ArrowDown, PageUp, PageDown, Home, and End. Native <input type="number"> does all of this natively and automatically triggers numeric keypads on mobile smartphones.
Semantic Target:<input type="number">
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
3
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
Native stepper controls & mobile numeric keypad
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern Medium Effort (~35 lines of JS + HTML)
Manual implementation of number stepping and constraint checking.
Structural landmarks define major regions of a webpage, allowing screen reader users to jump directly between sections. HTML5 landmark elements map natively to ARIA landmark roles.
First Rule Analysis:
Never use <div role="banner"> or <div role="main"> when you can use <header> and <main>. Modern HTML provides explicit elements for every major ARIA landmark: <header> (banner), <nav> (navigation), <main> (main), <aside> (complementary), <footer> (contentinfo), and the modern <search> element (search).
Use aria-label on <nav> elements (e.g. <nav aria-label="Main Navigation">) to distinguish multiple navigation landmarks on the same page.
Modern Semantic HTML5 Markup
<!-- Modern Semantic HTML5 Landmarks -->
<header>...</header>
<nav aria-label="Main">...</nav>
<main>...</main>
<aside>...</aside>
<search>...</search>
<footer>...</footer>
/* Note:
HTML5 sectioning elements map directly to accessibility API landmark roles in all modern browsers without any ARIA markup.
*/
A navigation trail showing the user’s location within a hierarchical site structure. The standard pattern combines semantic HTML <nav> and <ol> with aria-current="page".
First Rule Analysis:
The breadcrumb pattern represents the ideal synergy between semantic HTML and ARIA. Semantic HTML provides the container (<nav>), the ordered sequence of steps (<ol> and <li>), and the hyperlinks (<a>). ARIA provides the critical attribute aria-current="page" on the active link or element, informing assistive tech users that they are currently on that step.
Use a <span> with aria-current="page" for the last item rather than an <a> tag to avoid confusing unclickable self-links.
Modern Semantic HTML5 Markup
<!-- Same Semantic Implementation -->
<nav aria-label="Breadcrumb" class="breadcrumb-trail">
<ol>
<li><a href="/">Home</a></li>
<li><a href="/plain-english/">WCAG 3 Explorer</a></li>
<li><span aria-current="page">Pattern Lab</span></li>
</ol>
</nav>
/* Note:
Using a <span> for the current page avoids placing an unclickable or misleading link on the active page.
*/
A hierarchical list with parent and child items that can be expanded and collapsed, typical in IDE file trees and file managers.
First Rule Analysis:
For true application file explorer widgets, the APG Tree View pattern (role="tree", role="treeitem", aria-expanded) is required to deliver the expected single-tab-stop roving focus and hierarchical arrow navigation (ArrowRight expands/enters child, ArrowLeft collapses/jumps to parent). For simple hierarchical reading documents or site maps, nested <details> and <summary> elements provide an accessible zero-JS alternative.
Semantic Target:Nested <details> or ARIA role="tree"
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
📂 src/
📄 index.astro
📄 layout.astro
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
📂 src/
📄 index.astro
📄 layout.astro
Nested details works without JS, but lacks single-tab roving focus
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern Extreme Effort (~100 lines of recursive JS)
Hierarchical roving tabindex and recursive expand/collapse tracking.
A rotating or scrollable showcase of cards, images, or slides. Modern CSS Scroll Snap combined with semantic HTML buttons provides a high-performance, touch-friendly alternative to complex ARIA carousels.
First Rule Analysis:
The APG Carousel pattern involves complex ARIA live regions, role="roledescription", pause/play controls, and tablists. In modern web development, CSS Scroll Snap (scroll-snap-type: x mandatory) allows developers to build native momentum scrolling with GPU acceleration. Semantic <button> elements provide previous/next navigation and announced status without fragile custom DOM math.
A time-sensitive message that communicates important information to the user without receiving focus. HTML <output> natively maps to a polite live region, while role="alert" provides assertive interruption.
First Rule Analysis:
For general form feedback and calculated results, the native HTML <output> element provides an automatic live region with role="status" and aria-live="polite". When an urgent error or critical notification requires immediate screen reader interruption, the ARIA role="alert" (equivalent to aria-live="assertive") is specifically required.
Semantic Target:<output> or role="alert"
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
<output> maps natively to role="status" & aria-live="polite"
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern Medium Effort (~5 lines of JS + HTML)
Requires dynamic DOM node injection into existing live container.
Never place role="alert" on elements with keyboard focus; alerts are designed for passive non-focused announcement.
Modern Semantic HTML5 Markup
<!-- Semantic HTML Output Element -->
<output class="status-box" for="input-field" id="sem-output">
Changes saved successfully.
</output>
/* Note:
<output> natively maps to an accessible live region that notifies screen readers when content changes.
*/
W3C APG ARIA Pattern Markup & JavaScript
<!-- W3C APG ARIA Assertive Alert -->
<div role="alert" class="alert-box" id="apg-alert">
⚠️ Critical: Your session will expire in 2 minutes.
</div>
Key / Trigger
W3C APG ARIA Behavior
Semantic HTML5 Behavior
Focus / Tab
Alerts are NOT focused; screen readers announce automatically.
Output elements are not focused; announced via live region.
A contextual popup that displays information describing an element when focused or hovered. Modern CSS Anchor Positioning and Popover API dramatically simplify accessible tooltips.
First Rule Analysis:
The native HTML title attribute has significant accessibility defects: it does not work on touchscreens, cannot be resized, does not support custom contrast or keyboard delays, and violates WCAG 1.4.13 (Content on Hover or Focus). The APG pattern using aria-describedby and role="tooltip" remains essential, but modern CSS Anchor Positioning (anchor()) and the Popover API (popover="hint") now make the visual anchoring robust and pure CSS.
Semantic Target:aria-describedby + Popover API / title
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
Accessible contextual hint via aria-describedby
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
Note: title has mobile and contrast limitations
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern High Effort (~40 lines of JS + CSS positioning)
Requires coordinate math to avoid edge clipping and timer management.
Wiring & Implementation Requirements:
<button aria-describedby="tip-id">
<div role="tooltip" id="tip-id" hidden>
Event listeners for mouseenter, mouseleave, focus, blur, and Escape key dismissal
Keyboard Functionality:
Focus reveals tooltip
Escape dismisses tooltip without losing focus (WCAG 1.4.13)
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Reads tooltip text as accessible description after the button label.
🟢 Semantic HTML Equivalent Minimal (0 JS for title) (1 attribute)
Native title attribute.
Wiring & Implementation Requirements:
<button title="Tooltip text"> or popover="hint"
0 lines of JavaScript needed with title
Keyboard Functionality:
Hover or focus shows native tooltip in some browsers (unreliable in title)
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Reads title attribute if no other description exists.
⚠️
Real-World Limitations of Native Semantic HTML (Tooltip):
The HTML title attribute CANNOT be styled with CSS, does not work on mobile touchscreens, cannot be zoomed without page zoom, and cannot be dismissed with Escape in many browsers (violating WCAG 1.4.13).
A collection of commonly used controls arranged in a single tab stop where users navigate with arrow keys.
First Rule Analysis:
In complex applications (e.g. rich text editors), having 20 formatting buttons create 20 separate Tab stops severely degrades keyboard navigation efficiency. The APG Toolbar pattern groups related controls into a single tab stop: Tab enters the toolbar, Arrow keys navigate between controls, and Tab exits to the next document element.
Semantic Target:<fieldset> or <div role="toolbar">
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
Single Tab stop; use ← → arrow keys
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
Standard Tab sequence across individual buttons
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern High Effort (~40 lines of JS + HTML)
Required for complex applications to prevent Tab key fatigue.
Wiring & Implementation Requirements:
<div role="toolbar" aria-label="Formatting">
Roving tabindex across buttons (first button has tabindex="0", others have tabindex="-1")
Use role="toolbar" in rich applications (like text editors or drawing canvases) to keep the tab order clean.
Modern Semantic HTML5 Markup
<!-- Standard HTML Fieldset (Separate Tab Stops) -->
<fieldset class="toolbar-fieldset">
<legend class="sr-only">Text Formatting</legend>
<button type="button"><strong>B</strong></button>
<button type="button"><em>I</em></button>
<button type="button"><u>U</u></button>
</fieldset>
/* Note:
For simple forms, separate tab stops are acceptable; for rich apps, the APG roving toolbar is essential.
*/
A composite interactive widget containing tabular rows and cells navigable in two dimensions using arrow keys. Unlike static HTML tables, a grid treats cells as active focus targets.
First Rule Analysis:
Under the First Rule of ARIA, HTML <table> is specifically intended for presenting static structured tabular data, where screen readers operate in virtual reading mode. When building an editable spreadsheet or interactive data grid where users need 2D directional arrow-key navigation (Up/Down/Left/Right), cell editing (Enter/F2), and selection models without tabbing through every cell, HTML provides no native equivalent. The APG role="grid", role="row", and role="gridcell" with roving tabindex or aria-activedescendant are required.
Semantic Target:<table> with interactive cell controls
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
IDCriterionSeverityStatus
ISS-1011.4.3 ContrastHighOpen
ISS-1022.1.1 KeyboardCriticalIn Review
ISS-1034.1.2 Name/RoleMediumResolved
Use ↑ ↓ ← → arrow keys to navigate 2D cells; click/edit Status
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
WCAG Issue Tracker (Native HTML Table)
ID
Criterion
Severity
Status
ISS-101
1.4.3 Contrast
High
ISS-102
2.1.1 Keyboard
Critical
Standard Tab jumps between inputs; screen readers use native table keys
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern Extreme Effort (~150-250 lines of JS + ARIA logic)
2D coordinates tracking, roving tabindex matrix, edit mode state management, and assistive tech coordinate synchronization.
Wiring & Implementation Requirements:
Container element has role="grid" and aria-label or aria-labelledby.
Row elements have role="row".
Header cells have role="columnheader" or role="rowheader".
Data cells have role="gridcell".
Roving tabindex (tabindex="0" on active cell, tabindex="-1" on all others) or aria-activedescendant on the grid.
Arrow key handlers for 2D cell-by-cell directional navigation.
Single Tab stop: Tab moves focus into and out of the composite grid widget.
Keyboard Functionality:
Single Tab stop for entire grid container
Arrow keys (← ↑ → ↓) navigate cells in 2D space
Home / End moves to first / last cell in current row
Enter or F2 activates cell editing mode; Escape cancels
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Announces "Grid, N rows by M columns, row X, column Y: [content]". Changes to edit mode announced dynamically.
🟢 Semantic HTML Equivalent Minimal (0 JS) (~20 lines of HTML)
Standard native semantic table with embedded form controls.
Wiring & Implementation Requirements:
Standard <table> element with <thead>, <tbody>, <tr>, <th>, <td>.
Native <input> or <button> inside cells for interactivity.
Scope attributes (scope="col", scope="row") on headers.
Keyboard Functionality:
Tab moves sequentially across every single interactive element in the table
Arrow keys navigate inside individual form inputs rather than across table cells
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Screen reader virtual table navigation (Ctrl+Alt+Arrows in NVDA/JAWS; VO+Arrows in VoiceOver).
⚠️
Real-World Limitations of Native Semantic HTML (Grid (Data Grid & Editable Tables)):
Native tables have no single-tab roving keyboard navigation; every input in every cell is an individual Tab stop, making 50-row tables exhausting to tab through.
No built-in 2D arrow-key cell navigation without custom JavaScript.
A widget that presents a visible, scrollable list of options where users can select one or more items. Native HTML <select size="N"> provides this behavior with zero JavaScript.
First Rule Analysis:
Under the First Rule of ARIA, HTML provides a native, perfectly accessible listbox using <select size="N"> for single-selection and <select multiple size="N"> for multi-selection. The native element automatically handles keyboard navigation (Arrow keys, Home, End, Shift+Arrows for multi-select, type-ahead character search) and form submission. The APG ARIA pattern requires custom role="listbox", role="option", aria-selected, roving tabindex or aria-activedescendant, and extensive JavaScript.
Semantic Target:<select size="N"> or <select multiple>
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
✓WCAG 2.1 Level AA
✓WCAG 2.2 Level AA (Current Standard)
✓WCAG 2.2 Level AAA
✓WCAG 3.0 Bronze Draft
Navigate with ↑ ↓ arrow keys; Space to select
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
Native <select size="4"> provides zero-JS listbox with typeahead
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern High Effort (~50-80 lines of JS + ARIA)
Selection state management, roving tabindex or aria-activedescendant sync, scrollIntoView positioning, and type-ahead logic.
Wiring & Implementation Requirements:
Container element has role="listbox", tabindex="0", and aria-label or aria-labelledby.
Child item elements have role="option".
Selected option has aria-selected="true" (unselected have aria-selected="false").
For multi-selection, container has aria-multiselectable="true".
Roving tabindex or aria-activedescendant management in JavaScript.
Keyboard Functionality:
Single Tab stop on listbox container
Arrow keys (↑ / ↓) navigate and select options
Home / End moves to boundaries
Space toggles selection in multi-select mode
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Announces "Listbox, N items, [Option Name], X of N, selected".
🟢 Semantic HTML Equivalent Minimal (0 JS) (~5 lines of HTML)
Native declarative HTML with built-in form serialization.
Wiring & Implementation Requirements:
<select size="4"> for single-select scrollable listbox.
<select multiple size="4"> for multi-select listbox.
<option value="...">Option Label</option> tags.
Associated <label for="...">.
Keyboard Functionality:
Arrow keys navigate options natively
Shift+Arrow keys select contiguous ranges in multi-select
Native OS/browser listbox announcements with item count, position, and selected state.
⚠️
Real-World Limitations of Native Semantic HTML (Listbox):
Custom styling of native <option> elements (such as embedded avatars or custom badge markup) is historically restricted, though modern browser Customizable Select standards are closing this gap.
A desktop-application-style horizontal menu bar with dropdown submenus. For website navigation, semantic <nav> with standard links is strongly preferred over ARIA menubar.
First Rule Analysis:
The W3C APG explicitly cautions that the ARIA menubar pattern is intended for web applications mimicking desktop software menus (e.g. Google Docs File/Edit/View), NOT for website site navigation bars. Using role="menubar" on site navigation breaks standard tab navigation and hides links from screen reader landmark lists. For site navigation, the First Rule dictates using native <nav> with semantic lists (<ul>/<li>) and standard links (<a>) or Popover API buttons.
Unordered list (<ul>) and list items (<li>) for page structure.
Native links (<a href="...">) for pages.
Optional <button popovertarget="..."> for accessible disclosure submenus.
Keyboard Functionality:
Tab navigates sequentially through every navigation link
Enter activates link or opens popover dropdown
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Announces "Navigation landmark, list with N items, link, [Link Text]".
⚠️
Real-World Limitations of Native Semantic HTML (Menu and Menubar):
Hover-only CSS dropdown menus frequently collapse when users navigate with screen magnifiers or switch to keyboard; pairing with Popover API ensures click/Enter persistence.
A modal dialog that interrupts the user workflow to communicate an urgent message and require immediate confirmation or cancellation (e.g. confirming permanent deletion).
First Rule Analysis:
Native HTML <dialog> invoked via .showModal() natively traps keyboard focus, renders in the top-layer, dims background content with ::backdrop, handles Escape key dismissal, and restores focus upon closing. For an alert dialog, placing the autofocus attribute on the least destructive button (e.g. Cancel) ensures screen readers immediately announce the message while preventing accidental confirmation.
Semantic Target:<dialog> with autofocus on Cancel
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
⚠️
Discard Unsaved Changes?
You have 3 unsaved WCAG rule overrides. Leaving this view will permanently discard your work.
Focus placed on least destructive "Cancel" button; Esc closes
A scrollable list of articles that automatically loads new content as the user scrolls, supporting PageUp/PageDown article-to-article keyboard navigation.
First Rule Analysis:
Under the First Rule of ARIA, HTML provides the semantic building blocks for dynamic streams using <section> or <main> with child <article> elements. The ARIA role="feed" pattern is an enhancement layered on top of semantic articles that introduces PageUp/PageDown keyboard shortcuts for jumping between article boundaries and aria-busy="true" while fetching new batches.
Focus appearance, dragging movements, and accessible authentication are now formal recommendations.
WCAG 3 Working Draft Updated
Explorations into scoring models, task-based outcomes, and equity metrics continue.
Use Page Up / Page Down to jump between articles
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
WCAG 2.2 Recommendation
Standardized accessible authentication, focus appearance, and dragging.
WCAG 3 Working Draft
Evaluating holistic accessibility outcomes and disability equity.
Clean semantic HTML without complex feed roving focus JS
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern High Effort (~60-90 lines of JS + ARIA logic)
PageUp/PageDown focus management, scroll triggers, aria-busy states, and setsize calculation.
Wiring & Implementation Requirements:
Container has role="feed" and aria-label or aria-labelledby.
Each post item has role="article" and tabindex="0" (or contains focusable heading).
Articles specify aria-posinset and aria-setsize when total count is known.
While new articles are being fetched asynchronously, container has aria-busy="true".
PageUp / PageDown keyboard event listeners to jump focus between articles.
Keyboard Functionality:
PageUp / PageDown moves focus between article boundaries
Tab explores interactive buttons and links within current article
Ctrl+End jumps past the infinite feed
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Announces "Feed, Article X of Y, [Headline]". Dynamically announces when new articles are loaded.
🟢 Semantic HTML Equivalent Low (~15 lines of JS (IntersectionObserver))
Standard semantic HTML articles with standard web APIs.
Wiring & Implementation Requirements:
<section aria-label="Activity Feed"> or <main>.
Semantic <article> elements with header, time, and content.
IntersectionObserver for progressive infinite scroll.
Keyboard Functionality:
Standard Tab navigation across article interactive controls
Standard spacebar or PageDown viewport scrolling
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Announces section landmark and article landmarks with heading hierarchy.
⚠️
Real-World Limitations of Native Semantic HTML (Feed (Dynamic Content Stream)):
Native HTML does not provide keyboard shortcuts to jump directly from article to article; keyboard users must Tab through all controls in an article to reach the next one unless using heading navigation (H key in screen readers).
A slider featuring two or more draggable thumbs on a single rail (e.g. minimum and maximum price filter). HTML currently lacks a native dual-range input element.
First Rule Analysis:
HTML does not yet provide a native <input type="range" multiple> element. The accessible semantic alternative under the First Rule is pairing two native inputs: either two adjacent <input type="range"> sliders ("Minimum Budget" and "Maximum Budget") or two paired <input type="number"> controls. For a custom single-rail dual-thumb visual presentation, ARIA role="slider" attributes on both handles are required.
Semantic Target:Dual <input type="range"> or paired <input type="number">
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
Budget Range:$25 - $75
Tab to select thumb; ← → arrows adjust without crossing
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
Paired native <input type="range"> controls; full form and touch support
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern High Effort (~80-120 lines of JS + ARIA logic)
Dual thumb coordinate math, collision boundary checks, touch/mouse drag handlers, and twin ARIA state synchronization.
Wiring & Implementation Requirements:
Each thumb has role="slider", tabindex="0", aria-valuenow, aria-valuemin, aria-valuemax.
Explicit labels via aria-label (e.g. "Minimum Price" and "Maximum Price").
Collision prevention logic: Min thumb cannot exceed Max thumb value.
Active track highlight indicating selected range between the two thumbs.
Keyboard Functionality:
Tab moves between Min Thumb and Max Thumb
Arrow keys adjust focused thumb position
Home / End moves to permitted extremes
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Announces "Minimum price slider, $X, min $Y, max $Z" and "Maximum price slider, $A".
🟢 Semantic HTML Equivalent Low (~10 lines of HTML + 5 lines JS)
Two standard HTML range inputs with light synchronization logic.
Wiring & Implementation Requirements:
Two <input type="range"> elements with explicit <label> tags (Min & Max).
Or two <input type="number"> controls with min/max bounds.
Keyboard Functionality:
Native arrow key increments and Home/End on individual range sliders
Tab moves between the two inputs
Screen Reader (AT) Announcement:
🗣️ Screen Reader:
Native range slider announcements with complete browser accessibility.
⚠️
Real-World Limitations of Native Semantic HTML (Slider (Multi-Thumb Range)):
HTML has no single native control that paints two thumbs on one track; rendering a visual dual-thumb slider requires custom CSS or overlaying two transparent sliders.
Always provide numeric text readouts next to multi-thumb sliders so users know exact current values without having to calculate thumb pixel offsets.
Modern Semantic HTML5 Markup
<!-- Semantic HTML Paired Range Inputs -->
<fieldset class="semantic-range-pair">
<legend>Budget Range ($):</legend>
<label>Min: <input type="range" id="sem-min" min="0" max="100" value="20"></label>
<label>Max: <input type="range" id="sem-max" min="0" max="100" value="80"></label>
</fieldset>
/* Note:
Separate labeled range inputs work 100% natively on every mobile and desktop browser without JavaScript.
*/
A composite widget combining a tree view and a data grid, presenting hierarchical tabular data with expandable rows and 2D cell keyboard navigation.
First Rule Analysis:
HTML does not support a native hierarchical grid with row expansion and 2D cell arrow-key navigation. While nested <table> inside <details> can display hierarchical data statically, an application treegrid where users navigate cells across parent and child rows requires role="treegrid", role="row", aria-expanded, aria-level, and role="gridcell".
A movable separator between two panes that enables keyboard and mouse resizing of adjacent layout areas.
First Rule Analysis:
For simple layout resizing, modern CSS provides resize: horizontal with overflow: auto natively without any ARIA. For rich interactive application split panes, the ARIA separator pattern (role="separator", tabindex="0", aria-valuenow, aria-valuemin, aria-valuemax) communicates pane dimensions to screen readers and enables arrow key resizing. Alternatively, an accessible <input type="range"> labeled "Pane Divider" can semantically control flex-basis.
Semantic Target:CSS resize property or <input type="range"> controlling flex
⚡ Interactive Sandbox & Live AT Inspector
🟣 W3C APG (ARIA)Role, states & keyboard JS
Auditor View
Contrast: 7.2:1 (Pass AAA)
⋮
Component Code
<button role="switch">
Use ← → arrow keys to resize panes; Home/End for extremes
Live AT State:Loading state...
🟢 Semantic HTMLNative browser engine features
Resizable Box (CSS resize: horizontal)
Drag bottom-right handle or use arrow keys if focused.
Native CSS resize property requires 0 JavaScript to resize
Live AT State:Loading state...
🛠️ Implementation Blueprint: What's Required to Make It Work
🟣 W3C APG ARIA Pattern High Effort (~70-110 lines of JS + ARIA logic)