A bar of actions that is one tab stop, moved through with the arrow keys, such as the map's zoom and locate controls or a glass group in the top bar.
When to use
Use Toolbar for a bar of actions that is one tab stop, moved through with the arrow keys, such as a glass group of controls in the top bar.
| Use instead | When |
|---|---|
| MapControls | The bar holds the map's zoom, centre and view buttons |
| Button | One action stands alone, named in words |
| IconButton | One action stands alone, shown as an icon |
| Menu | More actions than the bar has room for open from one button |
| SegmentedControl | The buttons pick one of two to five ways to show one view |
Kongens Nytorv
Metro M1, M2 and M3.
Variants and states
| Rest | Disabled | |
|---|---|---|
| Default |
- Rest
- Disabled
Toolbar styles hover, pressed and focus on its inner parts, which a still preview can't reach, so this table shows rest and disabled only.
Props
| Name | Type | Default | Description |
|---|---|---|---|
orientation | 'horizontal' | 'vertical' | 'horizontal' | Which way the bar runs, and so which arrow keys move through it: Left and Right for horizontal, Up and Down for vertical. |
disabled | boolean | false | Whether every button in the toolbar is disabled. The buttons stay focusable unless their focusableWhenDisabled is false. |
children | ReactNode | — | The toolbar's ToolbarButtons, ToolbarGroups and ToolbarSeparators, in reading order. |
className | string | — | Reaches the root. className is merged after pn-Toolbar. |
style | CSSProperties | — | Reaches the root. className is merged after pn-Toolbar. |
ref | Ref<HTMLDivElement> | — | Reaches the root. className is merged after pn-Toolbar. |
orientation'horizontal' | 'vertical', default'horizontal'- Which way the bar runs, and so which arrow keys move through it: Left and Right for
horizontal, Up and Down forvertical. disabledboolean, defaultfalse- Whether every button in the toolbar is disabled. The buttons stay focusable unless their
focusableWhenDisabledisfalse. childrenReactNode, default —- The toolbar's
ToolbarButtons,ToolbarGroups andToolbarSeparators, in reading order. classNamestring, default —- Reaches the root.
classNameis merged afterpn-Toolbar. styleCSSProperties, default —- Reaches the root.
classNameis merged afterpn-Toolbar. refRef<HTMLDivElement>, default —- Reaches the root.
classNameis merged afterpn-Toolbar.
Use it
import { Toolbar } from '@mylder/perron'Ask your agent
get_reference({ library: "base-ui", component: "Toolbar" })Keyboard and ARIA
From the Base UI reference for Toolbar and the installed ToolbarRoot, ToolbarButton, ToolbarGroup, ToolbarSeparator and the composite root they build on. "From" says who does it.
| Key | Does | From |
|---|---|---|
Tab, Shift+Tab | Moves focus into the toolbar, to the item that last had it (the first enabled item at first), and out of it again: the toolbar is one tab stop | Base UI |
ArrowRight | In a horizontal toolbar, moves focus to the next item, wrapping from the last to the first while loopFocus is on; the previous item under an rtl DirectionProvider, which Perron doesn't set up | Base UI |
ArrowLeft | In a horizontal toolbar, moves focus to the previous item, wrapping from the first to the last while loopFocus is on; the next item under an rtl DirectionProvider, which Perron doesn't set up | Base UI |
ArrowDown, ArrowUp | In a vertical toolbar, move focus to the next and the previous item, wrapping while loopFocus is on | Base UI |
Enter, Space | Activate the focused button: fire onClick, or open the popup of a trigger given through render | The browser; Base UI for a non-button render |
Home and End do nothing: Base UI's toolbar doesn't turn them on (enableHomeAndEndKeys is off in the installed ToolbarRoot), and the component adds no keys of its own.
| Element | Role | Accessible name from | States announced |
|---|---|---|---|
root | toolbar, from Base UI | The caller's aria-label or aria-labelledby | aria-orientation |
button | button, native; role="button" when render gives a non-button | Its text content, the label's children; for an icon-only button, the caller's aria-label | Disabled: aria-disabled while focusable when disabled, else the native disabled; aria-pressed from selected, when given |
startIcon, endIcon | none: aria-hidden="true" | none | none |
group | group, from Base UI | The caller's aria-label, when the group needs one | none |
separator | separator, from Base UI | none | aria-orientation, across the toolbar's |
What axe won't catch, from the contract, each with how this component meets it:
- Everything the eye is told, the ear is told, for every shape each prop accepts: a button's label is the text it is named by, and an icon-only button's
aria-labelsays what its icon shows; the icons arearia-hidden;colorcarries emphasis, not meaning; a toggle's on fill is itsaria-pressed; disabled is announced byaria-disabledordisabled; the separator is announced as one. - Every landmark and named region has an accessible name: the toolbar is named by the caller's
aria-labeloraria-labelledby, which every story sets, so two toolbars on a screen tell themselves apart. - Every default label can be overridden: none here; the toolbar owns no strings.
- Every shape the type accepts renders, in every variant: a button's
children,startIconandendIconrender a string, an element and a list alike, in both colours and both orientations. - A hidden copy kept for animation is
aria-hidden, and a collapsed region isinert: none here; the toolbar keeps no hidden copy and collapses nothing. - Native semantics first: native
<button>s fromToolbar.Button, and Base UI'stoolbar,groupandseparatorroles, with ARIA only for the toolbar's and an icon-only button's names. - Focus moves in reading order and returns on close: the arrow keys move through the items in document order, swapped only under an
rtlDirectionProvider, which Perron doesn't set up, and the toolbar opens nothing of its own; a popup opened throughrenderreturns focus to its trigger, by Base UI. - Every target is at least
size.target-minsquare: the smallest target is an icon-only button,size.control(34 px) square. - Loops stop when the system asks for less motion: none here; the toolbar has no loop and no transition.
Owned strings
No owned strings: every word comes from the caller, as a button's children, an icon-only button's aria-label, or the toolbar's aria-label.
Do and don't
For a caller using the component, with the reason. Each row is a rule: a must row's Don't is never right, a should row's needs a reason, and Checked by says what catches the Don't in a caller's code.
| Rule | Level | Do | Don't | Checked by |
|---|---|---|---|---|
| DD-1 | must | Name every toolbar with aria-label or aria-labelledby, such as "Map controls", so a screen reader tells it from the next one | Leave a toolbar unnamed: two on a screen are both announced as "toolbar" | review |
| DD-2 | must | Put each action in a ToolbarButton, so the arrow keys reach it | Put a Button, an IconButton or a plain <button> straight into the toolbar: it falls out of the arrow-key order and adds a tab stop | review |
| DD-3 | must | Give an icon-only button an aria-label that names the action: "Zoom in" | Leave an icon-only button without one: its icon is aria-hidden, so the button has no name | review |
| DD-4 | must | Open a menu, popover or dialog through render, <ToolbarButton render={<Menu.Trigger />}>, and set disabled on the ToolbarButton, not the trigger | Disable the trigger itself: Base UI says the button then leaves the toolbar's arrow-key order | review |
| DD-5 | must | Wrap a button in a Tooltip with <Tooltip trigger={<ToolbarButton … />}>…</Tooltip>, the tooltip around the button | Pass the tooltip's trigger to ToolbarButton's render, as for popups | review |
| DD-6 | must | Give one button per screen color="brand", for its main action | Mark several toolbar buttons brand, or use it for emphasis: a second yellow action leaves neither the main one | review |
| DD-7 | must | Keep a disabled button focusable, the default, so it can explain itself through a tooltip | Restyle a disabled button with opacity: disabled is color.text.tertiary, a colour | review |
| DD-8 | must | Give a toggle in a toolbar, such as the map's 3D view, selected, held by the screen, and keep its name the same while on and off | Swap a toggle's name with its state, or draw its on look in the caller's CSS: selected sets aria-pressed and the on look together | review |
| DD-9 | should | Place the toolbar over the map in a pattern, which sets its position and stacking | Set a z-index or a margin from the screen edge on the toolbar itself: the component sizes to its content | review |