Toolbar
The W3C APG toolbar pattern. Its whole purpose is the tab sequence.
Example (a11y tier)
Tab into it once, then use the arrow keys. Tab again and you leave the toolbar entirely rather than walking the rest of it.
Import
import Toolbar from 'abaabil/toolbar' // structure onlyimport Toolbar from 'abaabil/toolbar/styled' // + CSSimport Toolbar from 'abaabil/toolbar/a11y' // + role, roving tabindex, arrowsOne stop instead of eight
A row of eight buttons is eight stops on the way to whatever comes after it. As a toolbar it is one, and the arrow keys move between the controls inside. That is the entire reason the pattern exists, and a toolbar that does not do it is a <div> with a role on it, which is worse than nothing: it announces a widget and then behaves like plain content.
Children, not an items array
Tabs and menu take an items array because their contents are uniform. A toolbar's are not: buttons, toggles, a select, a separator, whatever the job needs. So this takes children, and manages tabindex on its focusable descendants directly.
Cloning the children would have been the more React-shaped answer and does not work here, because it only reaches the top level and toolbar contents are often wrapped a level or two deep. The DOM is the source of truth for what is focusable instead, re-read on every keystroke so that controls appearing, disappearing or becoming disabled are picked up without anything having to announce it.
Controls that need the arrows keep them
A <select> or a text field inside a toolbar would be unusable if every arrow press moved focus out of it, so those keep their own arrow behaviour. A separator is an <hr>, which is the semantic way to say “these are different groups” and is turned on its side by CSS.
Props
| Prop | Type | Default | Tier | Description |
|---|---|---|---|---|
orientation | 'horizontal' | 'vertical' | 'horizontal' | all | Chooses the arrow pair and sets aria-orientation. |
className | string | — | all | Merged with the base class. |
label | string | — | a11y | Accessible name. An unnamed toolbar is announced as “toolbar” and nothing else. |
labelledBy | string | — | a11y | Id of an element naming it. |