ARIA Labels and Accessibility Attributes
This guide provides best practices for implementing ARIA labels and accessibility attributes in Sparkle documentation components to ensure WCAG 2.1 AA compliance.
Overview
Section titled “Overview”ARIA (Accessible Rich Internet Applications) labels and attributes help screen readers and other assistive technologies understand the purpose and state of interactive elements. All interactive components in the documentation must have proper accessibility attributes.
Core Principles
Section titled “Core Principles”1. All Interactive Elements Need Labels
Section titled “1. All Interactive Elements Need Labels”Every button, link, input, and interactive element must have a clear, descriptive label that explains its purpose.
Required Attributes:
aria-label: Provides accessible name when visible text is insufficientaria-labelledby: References another element’s text as the labelaria-describedby: References element(s) that describe the current element
2. Images Need Alternative Text
Section titled “2. Images Need Alternative Text”All images must have descriptive alternative text. Decorative images should be marked with aria-hidden="true".
For meaningful images:
<img src="diagram.png" alt="Architecture diagram showing component relationships" />For decorative images/icons:
<span aria-hidden="true">🎨</span><SunIcon aria-hidden="true" />3. Interactive States Must Be Communicated
Section titled “3. Interactive States Must Be Communicated”Screen readers need to know the current state of interactive elements.
Required State Attributes:
aria-pressed: For toggle buttons (true/false)aria-expanded: For collapsible content (true/false)aria-selected: For tabs and selectable items (true/false)aria-checked: For checkboxes and radio buttons (true/false/mixed)aria-disabled: For disabled elements (true/false)
Component-Specific Guidelines
Section titled “Component-Specific Guidelines”Buttons
Section titled “Buttons”All buttons must have clear labels that describe their action:
// ✅ Good - Clear action with aria-label<button onClick={handleCopy} aria-label="Copy code to clipboard" aria-pressed={copied}> <span aria-hidden="true">📋</span> Copy</button>
// ❌ Bad - No accessible label for icon-only button<button onClick={handleCopy}> 📋</button>Tabs and Tab Panels
Section titled “Tabs and Tab Panels”Tabs require proper ARIA roles and relationships:
// Tab list container<div role="tablist" aria-label="Component example variations"> {examples.map((example, index) => ( <button key={index} role="tab" aria-selected={index === activeIndex} aria-controls={`panel-${index}`} id={`tab-${index}`} aria-label={`View ${example.title} example`} > {example.title} </button> ))}</div>
// Associated tab panel<div role="tabpanel" id={`panel-${activeIndex}`} aria-labelledby={`tab-${activeIndex}`}> {activeExample.component}</div>Iframes
Section titled “Iframes”All iframes must have descriptive titles and aria-labels:
<iframe src={url} title="Interactive Storybook playground for Button component" aria-label="Button component Storybook interactive examples" loading="lazy"/>Expandable/Collapsible Content
Section titled “Expandable/Collapsible Content”Elements that show/hide content need aria-expanded:
<button onClick={toggleCode} aria-label={showCode ? 'Hide code example' : 'Show code example'} aria-expanded={showCode} aria-controls="code-container"> {showCode ? 'Hide Code' : 'Show Code'}</button>
<div id="code-container" role="region" aria-label="Code example"> {/* Code content */}</div>Form Controls
Section titled “Form Controls”All form inputs need associated labels:
// Using label element<label htmlFor="theme-select"> Select Theme <select id="theme-select" aria-label="Select theme"> <option value="light">Light</option> <option value="dark">Dark</option> </select></label>
// Using aria-label when label element isn't appropriate<input type="search" aria-label="Search documentation" placeholder="Search..."/>Radio Groups
Section titled “Radio Groups”Radio button groups need proper grouping and labeling:
<div role="radiogroup" aria-label="Theme selection"> <button type="button" role="radio" aria-checked={theme === 'light'} aria-label="Light theme" onClick={() => setTheme('light')} > Light </button> <button type="button" role="radio" aria-checked={theme === 'dark'} aria-label="Dark theme" onClick={() => setTheme('dark')} > Dark </button></div>Live Regions
Section titled “Live Regions”Dynamic content changes must be announced to screen readers:
<div role="status" aria-live="polite" aria-atomic="true"> {statusMessage}</div>
// For urgent alerts<div role="alert" aria-live="assertive"> {errorMessage}</div>Common Patterns
Section titled “Common Patterns”Icon-Only Buttons
Section titled “Icon-Only Buttons”When buttons contain only icons, always provide text alternatives:
<button aria-label="Close modal" onClick={handleClose}> <span aria-hidden="true">✕</span></button>Loading States
Section titled “Loading States”Communicate loading states to assistive technologies:
<button aria-busy={isLoading} aria-label={isLoading ? 'Loading...' : 'Submit form'} disabled={isLoading}> {isLoading ? 'Loading...' : 'Submit'}</button>Modal Dialogs
Section titled “Modal Dialogs”Modals require specific ARIA attributes:
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title" aria-describedby="dialog-description"> <h2 id="dialog-title">Confirm Action</h2> <p id="dialog-description">Are you sure you want to proceed?</p> <button onClick={handleConfirm}>Confirm</button> <button onClick={handleClose} aria-label="Close dialog">Cancel</button></div>Testing Checklist
Section titled “Testing Checklist”Before committing accessibility improvements, verify:
- All interactive elements have appropriate ARIA labels
- Button purposes are clear from labels alone
- Tab panels are properly associated with tabs
- Expandable content has
aria-expandedattributes - Form controls have associated labels
- Loading and error states are announced
- Icon-only buttons have text alternatives
- Decorative elements are marked with
aria-hidden="true" - Screen reader testing passes (see Accessibility Guide)
Automated Testing
Section titled “Automated Testing”Run accessibility audits to catch missing labels:
# Run Playwright accessibility testspnpm --filter @sparkle/docs a11y:playwright
# Run axe-core accessibility auditpnpm --filter @sparkle/docs a11y:auditResources
Section titled “Resources”- ARIA Authoring Practices Guide (APG)
- MDN ARIA Documentation
- WebAIM Screen Reader Testing
- WCAG 2.1 Guidelines
Related Guides
Section titled “Related Guides”- Accessibility Overview - Comprehensive accessibility compliance guide
- Keyboard Navigation - Focus management and keyboard patterns
- Heading Hierarchy - Semantic HTML structure