Experience System

Toolbar

Grouped controls for rich editors and tool palettes with roving focus, toggle groups, links, and separators.

Installation

The components are exported from @by/experience-system. Add the package with your package manager:

pnpm add @by/experience-system

In this monorepo, depend on the workspace package (for example via workspace:* or your catalog) so imports resolve to packages/experience-system.

Composition

Build a Toolbar from ToolbarToggleGroup / ToolbarToggleItem, ToolbarButton, ToolbarLink, ToolbarSeparator, and optionally ToolbarOverflowItem for non-primitive controls:

Toolbar
├── ToolbarToggleGroup
│   └── ToolbarToggleItem …
├── ToolbarSeparator (optional)
├── ToolbarButton | ToolbarLink …
├── ToolbarOverflowItem (optional, wraps non-primitive controls)
└── …

Other primitives with asChild triggers (for example DropdownMenu) can be composed inside the toolbar per Radix composition. See Radix Toolbar.

Usage

import {
  Toolbar,
  ToolbarButton,
  ToolbarOverflowItem,
  ToolbarSeparator,
  ToolbarToggleGroup,
  ToolbarToggleItem,
} from '@by/experience-system';

All toolbar parts are client components ('use client'). Use them inside a Client Component or a dynamic import when using the Next.js App Router.

<Toolbar aria-label="Actions" orientation="horizontal" loop>
  <ToolbarToggleGroup type="single" defaultValue="left" aria-label="Align">
    <ToolbarToggleItem value="left" aria-label="Left">
      L
    </ToolbarToggleItem>
    <ToolbarToggleItem value="right" aria-label="Right">
      R
    </ToolbarToggleItem>
  </ToolbarToggleGroup>
  <ToolbarSeparator />
  <ToolbarButton type="button">Save</ToolbarButton>
</Toolbar>

Examples

Overview

Multiple and single ToolbarToggleGroup regions, a ToolbarLink, and a ToolbarButton (same preview as at the top of the page).

Toggle groups

Two groups only—style (multiple) and alignment (single).

ToolbarButton with ToolbarLink items for secondary navigation.

Responsive — icon-only

All items are icon-only ToolbarButton elements. Each carries a menuItem prop so the toolbar can collapse overflowing items into the overflow dropdown. The first item uses visibility="always-visible" to pin it, and the last uses color="error" to indicate a destructive action.

Responsive — mixed controls

A toolbar that mixes ToolbarToggleGroup blocks, a plain Input wrapped in ToolbarOverflowItem, and labeled ToolbarButton actions. The Save button is pinned with visibility="always-visible" while Export uses visibility="always-hidden" so it always lives in the overflow menu.

API Reference

The tables below mirror the Radix UI Toolbar API. Subsection titles match @by/experience-system exports. ToolbarButton and ToolbarLink layer Button styles on Radix Toolbar.Button and Toolbar.Link. ToolbarButton, ToolbarSeparator, ToolbarToggleGroup, ToolbarToggleItem, and ToolbarOverflowItem all extend ToolbarOverflowableProps (menuItem, visibility) for responsive overflow behaviour.

ToolbarOverflowableProps

Shared interface extended by every toolbar primitive that participates in overflow.

PropTypeDefault
menuItemReact.ReactNode— — content rendered inside the overflow dropdown when this item is hidden
visibility'always-visible' | 'always-hidden' | undefinedundefined
  • 'always-visible' — pins the item so it is never collapsed into the overflow menu.
  • 'always-hidden' — always places the item in the overflow menu and never renders it in the toolbar.
  • undefined (default) — normal responsive behaviour; item collapses when the toolbar runs out of space.

Toolbar

PropTypeDefault
asChildbooleanfalse
orientationhorizontal | verticalhorizontal
dirltr | rtl
loopbooleantrue
Data attributeValues
data-slottoolbar
data-orientationhorizontal | vertical

ToolbarButton

PropTypeDefault
asChildbooleanfalse
variantButton variant valuesoutline
sizeButton size valuessm
colorButton color valuesneutral
menuItemReact.ReactNode
visibility'always-visible' | 'always-hidden' | undefinedundefined
Data attributeValues
data-slottoolbar-button
data-colormirrors color
data-orientationhorizontal | vertical
PropTypeDefault
asChildbooleanfalse
sizeButton size valuessm
Data attributeValues
data-slottoolbar-link
data-orientationhorizontal | vertical

ToolbarSeparator

PropTypeDefault
asChildbooleanfalse
menuItemReact.ReactNode
visibility'always-visible' | 'always-hidden' | undefinedundefined
Data attributeValues
data-slottoolbar-separator
data-orientationhorizontal | vertical

ToolbarToggleGroup

PropTypeDefault
asChildbooleanfalse
typesingle | multiple— (required)
valuestring or string[]
defaultValuestring or string[]
onValueChange(value: string | string[]) => void
disabledbooleanfalse
variantoutline | ghostghost
sizesm | md | lgsm
menuItemReact.ReactNode
visibility'always-visible' | 'always-hidden' | undefinedundefined
Data attributeValues
data-slottoolbar-toggle-group
data-orientationhorizontal | vertical

ToolbarToggleItem

PropTypeDefault
asChildbooleanfalse
valuestring— (required)
disabledboolean
variantoutline | ghostFrom group context
sizesm | md | lgFrom group context
Data attributeValues
data-slottoolbar-toggle-item
data-stateon | off
data-disabledPresent when disabled
data-orientationhorizontal | vertical

ToolbarOverflowItem

A data-carrier wrapper for non-primitive toolbar controls (e.g. Input, custom elements) that cannot accept the menuItem / visibility props directly. Place it as a direct child of <Toolbar> when overflow is enabled.

PropTypeDefault
childrenReact.ReactNode— (required) — rendered in the toolbar when space allows
menuItemReact.ReactNode— — rendered inside the overflow dropdown when this item is hidden
visibility'always-visible' | 'always-hidden' | undefinedundefined

ToolbarOverflowItem does not render any DOM element of its own; it delegates all rendering to the parent Toolbar.

Accessibility

Label the Toolbar and each ToolbarToggleGroup with aria-label (or aria-labelledby). Icon-only ToolbarToggleItem values need aria-label. Radix uses roving tabindex across toolbar items. See Radix Toolbar — accessibility.

Keyboard interactions

KeyDescription
TabMoves focus into the toolbar (first item).
SpaceActivates or toggles the focused item.
EnterActivates or toggles the focused item.
ArrowRight / ArrowDownMoves focus to the next item (depends on orientation).
ArrowLeft / ArrowUpMoves focus to the previous item.
HomeMoves focus to the first item.
EndMoves focus to the last item.

Source in the repo: packages/experience-system/src/components/Toolbar/Toolbar.tsx. Agent-oriented contracts: packages/experience-system/src/components/Toolbar/Toolbar.instructions.md.