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-systemIn 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).
Link
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.
| Prop | Type | Default |
|---|---|---|
menuItem | React.ReactNode | — — content rendered inside the overflow dropdown when this item is hidden |
visibility | 'always-visible' | 'always-hidden' | undefined | undefined |
'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
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
orientation | horizontal | vertical | horizontal |
dir | ltr | rtl | — |
loop | boolean | true |
| Data attribute | Values |
|---|---|
data-slot | toolbar |
data-orientation | horizontal | vertical |
ToolbarButton
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
variant | Button variant values | outline |
size | Button size values | sm |
color | Button color values | neutral |
menuItem | React.ReactNode | — |
visibility | 'always-visible' | 'always-hidden' | undefined | undefined |
| Data attribute | Values |
|---|---|
data-slot | toolbar-button |
data-color | mirrors color |
data-orientation | horizontal | vertical |
ToolbarLink
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
size | Button size values | sm |
| Data attribute | Values |
|---|---|
data-slot | toolbar-link |
data-orientation | horizontal | vertical |
ToolbarSeparator
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
menuItem | React.ReactNode | — |
visibility | 'always-visible' | 'always-hidden' | undefined | undefined |
| Data attribute | Values |
|---|---|
data-slot | toolbar-separator |
data-orientation | horizontal | vertical |
ToolbarToggleGroup
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
type | single | multiple | — (required) |
value | string or string[] | — |
defaultValue | string or string[] | — |
onValueChange | (value: string | string[]) => void | — |
disabled | boolean | false |
variant | outline | ghost | ghost |
size | sm | md | lg | sm |
menuItem | React.ReactNode | — |
visibility | 'always-visible' | 'always-hidden' | undefined | undefined |
| Data attribute | Values |
|---|---|
data-slot | toolbar-toggle-group |
data-orientation | horizontal | vertical |
ToolbarToggleItem
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
value | string | — (required) |
disabled | boolean | — |
variant | outline | ghost | From group context |
size | sm | md | lg | From group context |
| Data attribute | Values |
|---|---|
data-slot | toolbar-toggle-item |
data-state | on | off |
data-disabled | Present when disabled |
data-orientation | horizontal | 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.
| Prop | Type | Default |
|---|---|---|
children | React.ReactNode | — (required) — rendered in the toolbar when space allows |
menuItem | React.ReactNode | — — rendered inside the overflow dropdown when this item is hidden |
visibility | 'always-visible' | 'always-hidden' | undefined | undefined |
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
| Key | Description |
|---|---|
Tab | Moves focus into the toolbar (first item). |
Space | Activates or toggles the focused item. |
Enter | Activates or toggles the focused item. |
ArrowRight / ArrowDown | Moves focus to the next item (depends on orientation). |
ArrowLeft / ArrowUp | Moves focus to the previous item. |
Home | Moves focus to the first item. |
End | Moves 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.