| name | accessibility-audit |
| description | Check React components for WCAG accessibility compliance. Use when creating new components, modifying existing ones, or when the user asks about accessibility or a11y. |
Accessibility Audit Checklist
Use this checklist for every new or modified component.
Forms & Inputs
- Every
<input>, <select>, <textarea> has a <label> with htmlFor matching the input id
- Error messages use
role="alert" so screen readers announce them
- Disabled/loading buttons use
aria-busy and disabled
- Required inputs have the
required attribute
Buttons & Interactive Elements
- Every
<button> has type="button" (unless it is a form submit)
- Icon-only buttons have
aria-label with a descriptive text
- Buttons that control expandable regions have
aria-expanded and aria-controls
- All interactive elements have visible
focus-visible styles (use focus-visible:ring-2 focus-visible:ring-ring)
Navigation & Menus
- Mobile menus use
role="dialog" with aria-modal when open
- The menu trigger has
aria-expanded and aria-controls pointing to the menu id
- The overlay/backdrop has
aria-hidden when closed
- Focus is trapped inside the menu when open
- Focus returns to the trigger when the menu closes
Escape key closes the menu
- The
<nav> element has aria-label
Modals & Dialogs
- Use
role="dialog" with aria-modal="true" when open
- Focus the first focusable element inside on open
- Close on
Escape key
- Return focus to the trigger on close
- Lock body scroll while open (
document.body.style.overflow = 'hidden')
Loading States
- Loading indicators use
role="status" with aria-live="polite"
Landmarks
- Use semantic HTML:
<header>, <main>, <nav>, <section>, <article>, <footer>
<main> wraps the primary page content
- Each page has exactly one
<h1>
Color & Contrast
- Text meets WCAG AA contrast ratio (4.5:1 for normal text, 3:1 for large text)
- Do not rely solely on color to convey information
- Focus indicators must have sufficient contrast against the background
Focus Management
- When content changes dynamically (e.g., route transitions), move focus to the new heading/content area
- Use
tabIndex={-1} on containers that need programmatic focus
- Avoid
autoFocus unless the page has a single primary action (login form)
ARIA
- Use native HTML semantics first, ARIA only when semantics are insufficient
- Do not override native roles (e.g., do not add
role="button" to a <button>)
- Hidden elements use
aria-hidden not just CSS display/opacity