Toolbar
Group controls into one tab stop, with arrow keys to move between them.
import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarInput, ToolbarLink, ToolbarSeparator, ToolbarToggle } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use a toolbar for a dense set of controls that act on one thing: a text editor's formatting, a canvas's tools, a table's bulk actions. Keyboard users tab into it once and arrow along it, instead of tabbing through every key. For two or three buttons that belong together, a Button Group is enough.
import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator, ToolbarToggle } from '@youj/react'
import { BoldIcon, ItalicIcon, RedoIcon, UndoIcon } from '@youj/icons'
export function Formatting() {
return (
<Toolbar aria-label="Formatting">
<ToolbarGroup aria-label="History">
<ToolbarButton aria-label="Undo">
<UndoIcon />
</ToolbarButton>
<ToolbarButton aria-label="Redo" disabled focusableWhenDisabled>
<RedoIcon />
</ToolbarButton>
</ToolbarGroup>
<ToolbarSeparator />
<ToolbarToggle aria-label="Bold">
<BoldIcon />
</ToolbarToggle>
<ToolbarToggle aria-label="Italic">
<ItalicIcon />
</ToolbarToggle>
</Toolbar>
)
}ToolbarButton is an action and ToolbarToggle a two-state key (pressed, defaultPressed, onPressedChange). Both wear Toggle's key a step smaller, so actions and toggles line up. ToolbarLink and ToolbarInput join the same arrow-key order, and ToolbarGroup labels a cluster.
Description
A formatting toolbar with history buttons, text toggles, a link and a toggle group for alignment, all in one arrow-key path.
Put a Toggle Group in the toolbar for a single choice, like alignment or the active tool. Its items hand their focus to the toolbar, so they're part of the same arrow-key path, not a second tab stop.
A vertical tool rail with a tool toggle group and undo and redo buttons.
orientation="vertical" stacks the toolbar for a tool rail; the arrow keys become ↑ and ↓, and separators turn across it by themselves.
Code
toolbar-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propssize, size (2)
Props
ToolbarButton
| Prop | Type | |
|---|---|---|
size | ToolbarSize'default''sm''lg'The key's size, as Toggle's. default 'sm' | 'sm' |
ToolbarToggle
| Prop | Type | |
|---|---|---|
size | ToolbarSize'default''sm''lg'The key's size, as Toggle's. default 'sm' | 'sm' |
Toolbar takes Base UI's orientation, loopFocus (default true) and disabled. ToolbarButton and ToolbarToggle take focusableWhenDisabled, which keeps a disabled key in the arrow-key order so focus doesn't skip past it.
MotionPress, release and hover · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Presseach key scales to 0.97 while held | duration.instantease.standard80ms · cubic-bezier(0.2, 0, 0, 1) | 80mscubic-bezier(0.2, 0, 0, 1) | |
| Release and hoverscale back, background and text colors | duration.fastease.standard140ms · cubic-bezier(0.2, 0, 0, 1) | 140mscubic-bezier(0.2, 0, 0, 1) |
Reduced motion
Keys don't scale when pressed.
Reduced motion
Keys don't scale when pressed. Colors still change on hover and press, so what's pressed reads the same.
AccessibilityKeyboard, ARIA, focus
Accessibility
- The root is a
toolbar; name it witharia-label. It's a single tab stop, and the arrow keys move between its controls and wrap at the ends, mirrored in right-to-left layouts. - Toggles expose
aria-pressed. A disabled key withfocusableWhenDisabledstays focusable and reportsaria-disabled, so people can still find it and hear why it's there. - Name every icon-only key with
aria-label, and eachToolbarGroupwith the cluster's name.