Sikau

React · Day 22 · about 35 min

Accessible components

Tabs that work for keyboards and screen readers.

Pretty isn't enough

Clickable <div>s can't be reached by keyboard, and screen readers don't know a row of buttons is a set of tabs. React makes it easy to keep ARIA attributes in sync with state — so let's build components everyone can use.

Roles, state and keyboard

import { useState } from "react";

const TABS = ["Menu", "Hours", "Contact"];

export default function Tabs() {
  const [active, setActive] = useState(0);
  return (
    <div>
      <div role="tablist" aria-label="Restaurant info">
        {TABS.map((t, i) => (
          <button
            key={t}
            role="tab"
            id={"tab-" + i}
            aria-selected={i === active}
            aria-controls={"panel-" + i}
            tabIndex={i === active ? 0 : -1}
            onClick={() => setActive(i)}
          >
            {t}
          </button>
        ))}
      </div>
      <div role="tabpanel" id={"panel-" + active} aria-labelledby={"tab-" + active}>
        {TABS[active]} details…
      </div>
    </div>
  );
}
  • Use real <button>s and <a>s — they're focusable and work with Enter/Space for free.
  • Every input needs a <label>; every image an alt.
  • Check your work with only the keyboard, and with a screen reader (VoiceOver, NVDA).

The rest of this lesson

  • The tabs patternexplain
  • Roving tabIndex and arrow keysexplain
  • Better element?predict
  • Tab attributesmatch
  • Your turnwrite code
  • Badge quizquiz
  • What you learnedrecap

Continue this lesson free — run real code in your browser

Continue with Google

See all 24 lessons of React