Skip to content

Toolbar

General-purpose toolbar with start, center, and end content slots. Renders a `role="toolbar"` container with roving-tabindex keyboard navigation: the whole bar is one tab stop, and the arrow keys move between the controls inside it. The toolbar's `size` cascades through supported sizeable children and nested Toolbars so the bar's controls stay visually coordinated. A floating layer, Dialog, or Drawer starts a new cascade. Use it for contextual actions within a content area — above a table, as a card header with actions, or in a panel — not for app-wide navigation (use TopNav for that).

<Toolbar
label="Actions"
startContent={( <> <Button icon={Scissors} isIconOnly label="Cut" variant="ghost" /> <Button icon={Copy} isIconOnly label="Copy" variant="ghost" /> <Button label="Paste" variant="ghost" /> </> )}
endContent={( <Button icon={Settings} isIconOnly label="Settings" variant="ghost" /> )}
/>
<Toolbar
label="Document toolbar"
startContent={( <Button icon={ArrowLeft} isIconOnly label="Back" variant="ghost" /> )}
centerContent={<Text type="label">Q1 Planning Document</Text>}
endContent={( <> <Button label="Discard" variant="secondary" /> <Button label="Save" variant="primary" /> </> )}
/>
function Render() {
const [tab, setTab] = useState('overview');
return (
<div className={columnStyle}>
{(['sm', 'md', 'lg'] as const).map(size => (
<Toolbar
dividers={['bottom']}
endContent={
<>
<Button
icon={Download}
isIconOnly
label="Export"
variant="ghost"
/>
<Button label="New item" variant="primary" />
</>
}
key={size}
label={`Tab navigation (${size})`}
size={size}
startContent={
<Tabs label="Sections" onChange={setTab} value={tab}>
<Tab label="Overview" value="overview" />
<Tab label="Analytics" value="analytics" />
<Tab label="Settings" value="settings" />
</Tabs>
}
/>
))}
</div>
);
}
function Render() {
const [quantity, setQuantity] = useState<number | null>(1);
const [page, setPage] = useState(1);
return (
<Toolbar
label="Order controls"
size="sm"
startContent={
<>
<InputGroup isLabelHidden label="Order details">
<NumberInput
isLabelHidden
label="Quantity"
onChange={setQuantity}
value={quantity}
/>
<Select
isLabelHidden
label="Unit"
onChange={() => {}}
options={['Each', 'Case']}
value="Each"
/>
</InputGroup>
<ToggleButton isSelected label="Pinned" />
<SplitButton
items={[{label: 'Save as template'}]}
label="Save"
variant="primary"
/>
<Pagination onChange={setPage} page={page} totalPages={3} />
</>
}
/>
);
}
<Toolbar
endContent={
<Popover
content={
<TextInput
isLabelHidden
label="Overlay search"
onChange={() => {}}
placeholder="Defaults to md"
value=""
/>
}
label="Overlay controls"
padding={3}>
<Button label="Open md overlay" variant="secondary" />
</Popover>
}
label="Outer toolbar"
size="lg"
startContent={
<Toolbar
label="Nested toolbar"
startContent={
<>
<Button label="Inherited action" />
<ToggleButton label="Inherited toggle" />
</>
}
/>
}
/>
Table rows go here…
<Card style={{width: 480}}>
<Toolbar
dividers={['bottom']}
endContent={
<>
<Button icon={Filter} isIconOnly label="Filter" variant="ghost" />
<Button icon={Plus} isIconOnly label="Add user" variant="primary" />
</>
}
label="User list actions"
size="sm"
startContent={<Text type="label">Users</Text>}
/>
<div className={cardContentStyle}>
<Text type="body">Table rows go here…</Text>
</div>
</Card>
function Render() {
const [status, setStatus] = useState<string | null>(null);
return (
<Toolbar
endContent={
<SegmentedControl label="View" onChange={() => {}} value="list">
<SegmentedControlItem label="List" value="list" />
<SegmentedControlItem label="Grid" value="grid" />
</SegmentedControl>
}
label="Table filters"
size="sm"
startContent={
<>
<TextInput
isLabelHidden
label="Search"
onChange={() => {}}
placeholder="Search…"
value=""
/>
<Select
isLabelHidden
label="Status"
onChange={setStatus}
options={['Open', 'In progress', 'Done']}
placeholder="Status"
value={status}
/>
<Button label="Assignee" variant="secondary" />
</>
}
/>
);
}
<Toolbar
label="Bulk actions"
size="sm"
dividers={['top', 'bottom']}
startContent={( <> <Badge label="5 selected" /> <Button icon={Trash2} isIconOnly label="Delete" variant="ghost" /> <Button icon={Archive} isIconOnly label="Archive" variant="ghost" /> </> )}
endContent={<Button label="Deselect all" variant="ghost" />}
/>
Order table rows…
<Card style={{width: 640}}>
<Toolbar
dividers={['bottom']}
endContent={
<>
<Button
icon={RefreshCw}
isIconOnly
label="Refresh"
variant="ghost"
/>
<Button icon={Download} isIconOnly label="Export" variant="ghost" />
<Button label="New order" variant="primary" />
</>
}
label="Primary actions"
size="sm"
startContent={<Text type="label">Orders</Text>}
/>
<Toolbar
dividers={['bottom']}
endContent={<Button label="Clear filters" variant="ghost" />}
label="Filters"
size="sm"
startContent={
<>
<TextInput
isLabelHidden
label="Search orders"
onChange={() => {}}
placeholder="Search orders…"
value=""
/>
<Button label="Status" variant="secondary" />
<Button label="Date range" variant="secondary" />
</>
}
/>
<div className={cardContentStyle}>
<Text type="body">Order table rows…</Text>
</div>
</Card>
<div style={{height: 320, display: 'inline-flex'}}>
<Toolbar
dividers={['end']}
endContent={
<Button icon={Settings} isIconOnly label="Settings" variant="ghost" />
}
label="Canvas tools"
orientation="vertical"
startContent={
<>
<Button icon={Scissors} isIconOnly label="Cut" variant="ghost" />
<Button icon={Copy} isIconOnly label="Copy" variant="ghost" />
<Button icon={Trash2} isIconOnly label="Delete" variant="ghost" />
</>
}
/>
</div>

General-purpose toolbar with start, center, and end content slots. Renders a `role="toolbar"` container with roving-tabindex keyboard navigation: the whole bar is one tab stop, and the arrow keys move between the controls inside it. The toolbar's `size` cascades through supported sizeable children and nested Toolbars so the bar's controls stay visually coordinated. A floating layer, Dialog, or Drawer starts a new cascade. Use it for contextual actions within a content area — above a table, as a card header with actions, or in a panel — not for app-wide navigation (use TopNav for that).

PropTypeDefaultDescription
centerContentReactNodeContent centered between the start and end slots. When present, the layout switches to a three-track grid (1fr auto 1fr) so the center stays centered regardless of how wide the outer slots are.
classNamestringAdditional CSS class names applied to the root element.
data-testidstringTest ID applied to the root element.
dividersReadonlyArray<ToolbarDividerSide>Which sides get a hairline divider border.
endContentReactNodeContent aligned to the end (right in LTR).
gap0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 101Gap between items within each slot, using the spacing scale.
label*stringAccessible label for the toolbar.
orientation"horizontal" | "vertical"'horizontal'Layout and keyboard-navigation orientation. Controls which arrow keys move focus between items.
refRef<HTMLDivElement>Ref forwarded to the root element.
size"sm" | "md" | "lg"The enclosing Toolbar size, otherwise 'md'Toolbar size. Supported sizeable children inherit it as their default, including nested Toolbars; Button, ButtonGroup, SplitButton, and ToggleButton; InputGroup, TextInput, NumberInput, Select, MultiSelect, AutocompleteInput, TagsInput, TextArea, and SearchFilterInput; plus SegmentedControl, Tabs, and Pagination. Floating layers, Dialogs, and Drawers start a new size cascade.
startContentReactNodeContent aligned to the start (left in LTR).
styleCSSPropertiesInline styles applied to the root element.