All guidesAccessibility

Accessible components with React and Tailwind

7 min read

Accessibility is not a topping you sprinkle on at the end. It grows out of a component's structure. Those who use semantic HTML, make focus visible and take the keyboard seriously build interfaces that work for more people. This guide shows the most important building blocks with React and Tailwind CSS.

Start with semantic HTML

The right element is half the battle. A button is a button, not a div with onClick. Native elements come with focus behavior, keyboard operation and the right role for screen readers built in. That saves you a lot of manual follow-up work.

Structure matters too. Headings in a logical order, nav for navigation, main for the main content and lists for enumerations give assistive technologies a map of your page. In React that costs nothing extra, you simply choose the fitting tag.

Make focus visible

Those navigating by keyboard must see where they currently are. So never remove the focus ring without a replacement. In Tailwind you control it deliberately through focus-visible, so it appears on keyboard use but does not disturb on mouse clicks.

A class like focus-visible with ring-2 and a clear ring color is often enough. Make sure there is enough contrast to the background so the state stays clear even on light surfaces. A clearly visible focus is a sign of care, not a flaw.

Use ARIA only when needed

ARIA attributes add meaning that does not come from the HTML alone. But the first rule is: no ARIA is better than wrong ARIA. Where a native element suffices, you need no extra role.

ARIA becomes useful for custom widgets. A toggle gets aria-pressed, an expandable menu aria-expanded, a purely decorative icon aria-hidden. For buttons without visible text, aria-label provides an understandable label. Set these attributes deliberately and keep them in sync with your component's actual state.

Consider keyboard operation

Everything that works with the mouse should also work with the keyboard. Native buttons and links already respond to Enter and Space. If you build interactive elements yourself, you have to provide these keys and a sensible tab order on your own.

For overlays like dialogs, focus comes into play. On opening it moves into the dialog, on closing back to the triggering element, and while it is open it stays trapped inside the dialog. This focus management decides whether a component is truly operable.

Check contrast and colors

Text must stand out clearly from the background. As a guideline, at least 4.5 to 1 for normal text and 3 to 1 for large type. Very light grays on white look elegant but often fail this test.

Color should also never be the only carrier of information. An error state needs a word or an icon next to the red, an active link more than just a different color. That keeps your interface understandable for people with limited color vision too.

Account for images and motion

Every content-carrying image needs a short, fitting alternative in the alt attribute. Purely decorative images get an empty alt so screen readers skip them and do not interrupt the reading flow with decoration.

Motion should be possible to turn off. Through prefers-reduced-motion and the hook useReducedMotion you offer a calm variant. Together with good contrast and clear structure your component becomes usable for many more people.