Accessibility Standards & Requirements
MANDATORY Accessibility Compliance
- ALL new components MUST meet WCAG 2.1 AA accessibility standards - no exceptions.
- Accessibility features must be implemented BEFORE code is considered complete.
- Design components to be accessible by default, not as an afterthought.
ARIA Attributes & Semantic HTML
- Landmark Roles: Use proper HTML5 semantic elements (
header, main, nav, aside, footer) with appropriate role attributes.
- ARIA Labels: Provide descriptive
aria-label attributes for interactive elements where text content is insufficient.
- ARIA States: Use
aria-expanded, aria-current, aria-hidden, aria-live appropriately for dynamic content.
- ARIA Relationships: Implement
aria-labelledby, aria-describedby, aria-controls for element relationships.
- Screen Reader Support: All interactive elements must have meaningful labels for screen readers.
Keyboard Navigation Requirements
- Focus Management: Implement proper focus trapping in modals, overlays, and navigation menus.
- Focus Indicators: ALL focusable elements must have visible focus indicators (use consistent
focus:ring-2 focus:ring-blue-500 focus:ring-offset-2).
- Tab Order: Ensure logical tab order throughout the application.
- Arrow Keys: Implement arrow key navigation for menus, lists, and grouped controls.
- Escape Key: Support Escape key to close modals, menus, and overlays.
- Enter/Space: Support Enter and Space keys for button activation.
Dynamic Content & Live Regions
- ARIA Live: Use
AccessibilityAnnouncer component for dynamic content updates.
- Status Messages: Announce navigation state changes, form submissions, and loading states.
- Live Region Types: Use
aria-live="polite" for non-urgent updates, aria-live="assertive" for urgent messages.
- Alternative Text: ALL images must have descriptive alt text that conveys meaning, not just description.
- Decorative Images: Use
aria-hidden="true" or empty alt="" for purely decorative images.
- Complex Images: Provide detailed descriptions for charts, graphs, and complex visuals.
Focus Trapping
- Modal Focus: Use
useFocusTrap hook for all modal dialogs and overlays.
- Navigation Focus: Implement focus trapping in mobile navigation menus.
- Focus Restoration: Always restore focus to the triggering element when closing modals/menus.
Color & Contrast
- Color Contrast: Ensure minimum 4.5:1 contrast ratio for normal text, 3:1 for large text.
- Color Independence: Never rely solely on color to convey information.
- Dark Mode: Maintain accessibility standards in both light and dark themes.
Component-Specific Requirements
Interactive Components
- All buttons, links, and form controls must have focus indicators.
- Use consistent focus ring styling:
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2.
- Provide descriptive labels for screen readers.
Navigation Components
- Implement arrow key navigation for menu items.
- Support Home/End keys for jumping to first/last items.
- Use proper ARIA expanded states for collapsible sections.
- Announce navigation state changes with live regions.
- Associate labels with form controls using
htmlFor or aria-labelledby.
- Provide error messages with
aria-describedby.
- Use fieldsets and legends for grouped form controls.
- Implement client-side validation with accessible error announcements.
Examples of Proper Implementation
<button
type="button"
aria-label="Close navigation menu"
aria-expanded={isOpen}
aria-controls="navigation-menu"
className="focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-none"
onClick={handleClose}
>
<X aria-hidden="true" />
</button>
Navigation with Keyboard Support
<nav role="navigation" aria-label="Course navigation">
<ul role="menubar">
<li role="none">
<Link
role="menuitem"
href="/learn/course/intro"
className="focus:ring-2 focus:ring-blue-500 focus:outline-none"
aria-current={isActive ? "page" : undefined}
>
Introduction
</Link>
</li>
</ul>
</nav>
Modal with Focus Trapping
const modalRef = useFocusTrap(isOpen);
<div
ref={modalRef}
role="dialog"
aria-labelledby="modal-title"
aria-modal="true"
aria-hidden={!isOpen}
>
<h2 id="modal-title">Modal Title</h2>
{/* Modal content */}
</div>;