FeaturesPricingAudit GuideFree StatementDashboard →

React Accessibility: Building WCAG 2.1 AA Compliant Components

Build accessible React components following WCAG 2.1 AA standards. Include proper ARIA, keyboard navigation, and focus management in React apps.

8 min read

Introduction

React is powerful for building dynamic UIs but accessibility isn't automatic. 79% of React applications fail basic WCAG 2.1 AA tests. Missing ARIA attributes, focus management issues, and dynamic content problems plague React apps. Our guide helps developers build accessible React components and applications from day one.

Enterprise React apps face increasing ADA scrutiny. Recent lawsuits target major SaaS platforms using React. Poor React accessibility excludes 15-20% of potential users and damages employer brand. Accessibility is a engineering quality standard, not an afterthought.

Legal Risk: Websites built on React are subject to ADA Title III requirements. Over 850+ lawsuits target React sites annually. 79% of sites are non-compliant.

Common Accessibility Issues

Missing ARIA Labels and RolescriticalWCAG 2.1 AA 1.3.1

React components lack aria-label, aria-labelledby, and proper roles. Custom components don't announce their purpose to screen readers.

Focus Management IssuescriticalWCAG 2.1 AA 2.4.3

Dynamic content doesn't move focus when modals open. Focus trapping is broken. Users can't navigate to new content.

No Keyboard SupportcriticalWCAG 2.1 AA 2.1.1

Custom React components respond only to clicks. Arrow keys, Tab navigation, and Enter/Space don't work. Keyboard users are locked out.

Image Alt Text MissingcriticalWCAG 2.1 AA 1.1.1

React image components render <img> tags without alt attributes. Dynamic images lack descriptions.

Inaccessible Form ValidationseriousWCAG 2.1 AA 3.3.1

Form errors aren't announced. Validation messages are visual-only. Field requirements aren't programmatically indicated.

How to Fix Common Issues

Missing ARIA Labels on Custom Button

Before (inaccessible)
export function CloseButton() {
  return <button onClick={() => close()}>×</button>
}
After (accessible)
export function CloseButton() {
  return <button onClick={() => close()} aria-label="Close dialog">×</button>
}

Icon buttons need aria-label. Always label custom controls with aria-label, aria-labelledby, or aria-describedby. Screen reader users must know what each button does.

Focus Not Managed in Modal

Before (inaccessible)
export function Modal({ isOpen, children }) {
  return isOpen && <div>{children}</div>
}
After (accessible)
export function Modal({ isOpen, children }) {
  const dialogRef = useRef(null)
  useEffect(() => {
    if (isOpen) dialogRef.current?.focus()
  }, [isOpen])
  return isOpen && <dialog ref={dialogRef}>{children}</dialog>
}

Use useRef and useEffect to move focus when modals open. Use <dialog> element for semantic HTML. Return focus to trigger element on close.

Missing Alt Text on Images

Before (inaccessible)
<img src={productImage} />
After (accessible)
<img src={productImage} alt={`${productName} - ${productColor} available in sizes S-XXL`} />

Always include alt attribute on <img> tags. Alt text should describe the image meaningfully. Empty alt (alt="") for decorative images only.

React-Specific Notes

React developers should use accessible React libraries: Headless UI, Radix UI, React Aria (Adobe), and React Hook Form provide accessible components. Install eslint-plugin-jsx-a11y to catch accessibility issues during development. Use Testing Library with testing-library/jest-dom for accessibility testing. Avoid inline onclick handlers; use semantic HTML.

Accessibility Statistics

850+

Lawsuits per year

79%

Sites non-compliant

60-90 hours

Avg fix time

Frequently Asked Questions

Should I use accessible component libraries?
Yes. Headless UI, Radix UI, and React Aria provide accessible components. Building from scratch introduces accessibility bugs. Reuse tested components.
How do I test accessibility in React?
Use jest-axe for automated testing. Add @testing-library/jest-dom assertions. Test keyboard navigation manually. Use axe DevTools browser extension.
What's the difference between aria-label and aria-labelledby?
aria-label directly names an element. aria-labelledby links to another element's ID for naming. Use aria-labelledby when a visible label exists.
How do I manage focus in React?
Use useRef to store element references. Use useEffect to call .focus() when needed. Reset focus on unmount. Avoid focus trapping unless building a modal.

Check your website for free

Get your ADA, WCAG, privacy & security score in 90 seconds.

No credit card
WCAG 2.1
ADA
Privacy

Related guides