Skip to content

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/react

For 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.

Reference

Propssize, size (2)

Props

ToolbarButton

ToolbarButton props
PropType
sizeToolbarSize
'default''sm''lg'

The key's size, as Toggle's.

default 'sm'

'sm'

ToolbarToggle

ToolbarToggle props
PropType
sizeToolbarSize
'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

Motion tokens
MomentTokens
Presseach key scales to 0.97 while held
duration.instantease.standard

80ms · cubic-bezier(0.2, 0, 0, 1)

80mscubic-bezier(0.2, 0, 0, 1)
Release and hoverscale back, background and text colors
duration.fastease.standard

140ms · 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 with aria-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 with focusableWhenDisabled stays focusable and reports aria-disabled, so people can still find it and hear why it's there.
  • Name every icon-only key with aria-label, and each ToolbarGroup with the cluster's name.