Tabs
The W3C APG tabs pattern: roles, roving tabindex, arrow keys, both orientations. The one component here whose a11y tier does substantial work, because tabs have no native element to build on.
Example (a11y tier)
Arrow keys move between these tabs, Home and End jump to the ends, and both wrap. Tab moves past the tablist entirely, not through every tab in it.
Import
import Tabs from 'abaabil/tabs' // structure + selection, no ARIAimport Tabs from 'abaabil/tabs/styled' // + CSSimport Tabs from 'abaabil/tabs/a11y' // + APG roles, roving tabindex, arrow keysThe exception to the library's usual shape
Most components here are thin because the browser already does the work. Tabs are the counterexample: there is no native tabs element, so every tier is a client module, and the a11y tier is the largest in the library after the combobox. It is worth saying plainly, because a library that only claims wins is not describing anything real.
What the a11y tier adds is everything a browser would have given you for free if this were a native element: the tablist, tab and tabpanel roles; aria-selected; each tab paired to its panel with aria-controls and aria-labelledby; a roving tabindex so Tab steps past the tablist rather than through it; and the arrow keys, which follow orientation so the announced aria-orientation is not a lie.
Vertical
Arrow keys move between these tabs, Home and End jump to the ends, and both wrap. Tab moves past the tablist entirely, not through every tab in it.
Up and Down replace Left and Right, and the marker moves to the inline-start edge, which is the side the reading direction starts from in both LTR and RTL.
Props
| Prop | Type | Default | Tier | Description |
|---|---|---|---|---|
items | Array<{ key?, label, children? }> | — | all | One entry per tab. |
defaultIndex | number | 0 | all | Tab selected on first render. |
onChange | (index) => void | — | all | Called with the newly selected index. |
className | string | — | all | Merged with the base class. |
label | string | — | a11y | Accessible name for the tablist. |
labelledBy | string | — | a11y | Id of an element naming the tablist, when a visible heading already does. |
orientation | 'horizontal' | 'vertical' | 'horizontal' | a11y | Chooses the arrow pair and sets aria-orientation. |
activation | 'automatic' | 'manual' | 'automatic' | a11y | automatic selects as focus moves. manual moves focus without selecting; Enter or Space commits. |
Uncontrolled, like the combobox: observe the selection through onChange rather than driving it from outside.