React Accessibility: A Practical Guide to Building Inclusive UIs

Build inclusive React interfaces with semantic HTML, accessible names, visible focus, and ARIA only when a native element cannot express the behavior.

8 min read

React accessibility means building components that everyone can use, including people who navigate with a keyboard or a screen reader. The fastest way there is semantic HTML first, with ARIA only when a native element cannot express the behavior.

Use semantic HTML first

A native element such as a button, input, or select already has keyboard support, a role, and a name that assistive technology understands. Rebuilding that behavior on a div means writing all of it yourself and getting part of it wrong. Native elements are also more reliable than hand-built ones because browsers maintain their behavior across updates.

Use a button for actions, a link for navigation, and a form element for input. Landmarks such as main, header, and nav give screen reader users a way to jump around the page without any extra code. The same rule applies to lists and tables: use ul, ol, and table elements so their structure is announced rather than rebuilt from generic divs.

Give every control an accessible name

A form field or button needs a name that a screen reader can announce. The simplest way is a label wrapping the control.

App.jsxApp.jsx
function EmailField() {
  return (
    <label>
      Email address
      <input type="email" name="email" />
    </label>
  );
}

The label text becomes the input's accessible name, so a screen reader announces "Email address" when the field receives focus. A placeholder is not a label, because it disappears while the user types.

Buttons get their name from their text, and an icon-only button needs an aria-label so the name is not empty. A visible label also helps sighted users, so prefer it over aria-label when space allows.

Keep focus visible and managed

Keyboard users need to see where they are. Never remove the focus outline, and keep the tab order matching the visual order.

When a modal opens, move focus into it, and when it closes, return focus to the control that opened it. A skip link at the top of the page lets keyboard users jump past repeated navigation to the main content.

The details for interactive controls are in How to Make Clickable Elements Accessible in React, and the keyboard patterns are in Keyboard Navigation Patterns for React Components.

Use headings and landmarks

Screen reader users often navigate by headings and landmarks. Use one main heading per page, keep heading levels in order, and wrap navigation in nav and main content in main.

Skipping a level, such as jumping from h1 to h3, makes the structure harder to follow. A consistent structure also helps reviewers and automated tools spot missing sections.

ARIA is the last resort

The first rule of ARIA is to use a native element when one exists. A progress bar is a good example: the native progress element already carries the role and value semantics.

App.jsxApp.jsx
function UploadProgress({ value }) {
  return (
    <progress aria-label="Upload progress" value={value} max={100}>
      {value}%
    </progress>
  );
}

The progress element carries the role and value automatically, but the text between the tags is only a fallback for old browsers, not an accessible name. The aria-label gives it one.

Adding a role and ARIA attributes to a div would only re-create, by hand, what the browser already provides. Incorrect ARIA is worse than no ARIA, because it misleads assistive technology.

Landmarks and native controls already expose roles, so do not duplicate them with role attributes. When a widget truly has no native equivalent, ARIA in React: When Native HTML Is Not Enough shows how to add it correctly.

Test with the keyboard

Automated checks catch missing labels and contrast problems, but the keyboard test finds the issues that matter most. Tab through the page and confirm every focusable control is reachable, visible, and operable. A tab order that matches the visual order, with a visible focus ring, is the sign the page is keyboard-friendly.

Forms deserve the same pass. A validation message must be read by a screen reader and not communicated by color alone. Run the pass before shipping, not after a complaint.

Rune AI

Rune AI

Key Insights

  • Prefer native elements such as button and input over repurposed divs.
  • Give every form control and image an accessible name or text.
  • Keep focus visible and order it to match the page.
  • Use ARIA only when no native element expresses the behavior.
  • Test with a keyboard, not only with automated tools.
RunePowered by Rune AI

Frequently Asked Questions

Does accessibility require a lot of ARIA?

Usually the opposite. Most accessibility comes from using the right native elements. ARIA is a fallback for widgets HTML cannot express, and incorrect ARIA makes things worse.

How do I know my component is accessible?

Start by using it with only a keyboard. Tab through the controls, check focus is visible, and confirm every form field has an accessible name. Automated tools help, but keyboard testing finds the most real issues.

Conclusion

Accessible React starts with semantic HTML, clear accessible names, and predictable focus. Reach for ARIA only when a native element cannot express the behavior, and test with a keyboard before calling the work done.