XDSToolbar@xds/core · Toolbar

Usage

Toolbar is a horizontal bar with left, center, and right areas. Use it for contextual actions within a content area — above a table, inside a card, or in a panel — not as a page-level header. Set the size once on the toolbar and all buttons, inputs, and tabs inside it match automatically.

Best practices

GuidancePractices
DoPut secondary actions like "Back" on the left, and primary actions like "Save" on the right.
DoMake temporary toolbars like bulk selection visually distinct so users can tell they're contextual — for example, with a background color or border.
DoVisually separate the toolbar from the content below it — with a divider, a background variant, or both.
DoUse Toolbar as a card header when the header has interactive actions like filter or add — it gives you slot layout, keyboard navigation, and size cascading. If the header is just a title with no actions, a LayoutHeader or Section is enough.
Don'tPut too many actions in one toolbar — move less common items into a MoreMenu.
Don'tSet size on individual child buttons — set it once on the toolbar and it cascades automatically.
Don'tUse Toolbar for app-wide navigation like main menu links or sign out — use TopNav or LayoutHeader for that.

Import

ts
import {XDSToolbar} from '@xds/core/Toolbar'

Props

PropTypeDescription
labelrequired
stringAccessible label for the toolbar, applied as aria-label.
startContent
ReactNodeContent aligned to the start (left in LTR).
centerContent
ReactNodeCentered content. Switches layout to CSS grid (1fr auto 1fr).
endContent
ReactNodeContent aligned to the end (right in LTR).
density
'compact' | 'default' (default: 'default')Toolbar density. Controls minimum height.
gap
SpacingStep (default: 2)Gap between items within each slot.
orientation
'horizontal' | 'vertical' (default: 'horizontal')Orientation for keyboard navigation. Controls arrow key direction.
variant
XDSSectionVariant (default: 'transparent')Visual variant passed to XDSSection.
xstyle
StyleXStylesStyleX styles for layout customization. Must be a stylex.create() value.

Sub-components

Toolbar is a compound component with 1 sub-component.

XDSToolbar

General-purpose toolbar container with three content slots and roving tabindex.
PropTypeDescription
labelrequired
stringAccessible label for the toolbar, applied as aria-label.
startContent
ReactNodeContent aligned to the start (left in LTR).
centerContent
ReactNodeCentered content. Switches layout to CSS grid (1fr auto 1fr).
endContent
ReactNodeContent aligned to the end (right in LTR).
density
'compact' | 'default' (default: 'default')Toolbar density. Controls minimum height.
gap
SpacingStep (default: 2)Gap between items within each slot.
orientation
'horizontal' | 'vertical' (default: 'horizontal')Orientation for keyboard navigation. Controls arrow key direction.
variant
XDSSectionVariant (default: 'transparent')Visual variant passed to XDSSection.
xstyle
StyleXStylesStyleX styles for layout customization. Must be a stylex.create() value.

Examples

Common configurations, variations, and states.
Toolbar — Bulk ActionsA compact toolbar with the wash variant for showing bulk selection actions. Use when the user selects multiple items in a list or table and needs quick access to batch operations.
tsx
'use client';
import {useState} from 'react';
import {XDSToolbar} from '@xds/core/Toolbar';
import {XDSButton} from '@xds/core/Button';
import {XDSIcon} from '@xds/core/Icon';
import {XDSBadge} from '@xds/core/Badge';
import {XDSTable} from '@xds/core/Table';
import {useXDSTableSelection, useXDSTableSelectionState} from '@xds/core/Table';
import {TrashIcon, ArchiveBoxIcon} from '@heroicons/react/24/outline';
const DATA = [
{id: '1', name: 'Alex Johnson', status: 'Active', role: 'Admin'},
{id: '2', name: 'Sam Rivera', status: 'Active', role: 'Editor'},
{id: '3', name: 'Jordan Lee', status: 'Invited', role: 'Viewer'},
{id: '4', name: 'Taylor Kim', status: 'Active', role: 'Editor'},
{id: '5', name: 'Casey Park', status: 'Active', role: 'Viewer'},
];
export default function ToolbarBulkActions() {
const [selectedKeys, setSelectedKeys] = useState<Set<string>>(
() => new Set(['1', '3', '5']),
);
const {selectionConfig} = useXDSTableSelectionState({
data: DATA,
idKey: 'id',
selectedKeys,
setSelectedKeys,
});
const selectionPlugin = useXDSTableSelection(selectionConfig);
return (
<>
{selectedKeys.size > 0 && (
<XDSToolbar
label="Bulk actions"
size="sm"
variant="wash"
startContent={
<>
<XDSBadge label={`${selectedKeys.size} selected`} />
<XDSButton
label="Delete"
variant="ghost"
icon={<XDSIcon icon={TrashIcon} />}
isIconOnly
/>
<XDSButton
label="Archive"
variant="ghost"
icon={<XDSIcon icon={ArchiveBoxIcon} />}
isIconOnly
/>
</>
}
endContent={
<XDSButton
label="Deselect all"
variant="ghost"
onClick={() => setSelectedKeys(new Set())}
/>
}
/>
)}
<XDSTable
idKey="id"
columns={[
{key: 'name', header: 'Name'},
{key: 'status', header: 'Status'},
{key: 'role', header: 'Role'},
]}
data={DATA}
plugins={{selection: selectionPlugin}}
/>
</>
);
}
Toolbar — Card Header
tsx
'use client';
import {XDSToolbar} from '@xds/core/Toolbar';
import {XDSButton} from '@xds/core/Button';
import {XDSIcon} from '@xds/core/Icon';
import {XDSHeading} from '@xds/core/Text';
import {XDSCard} from '@xds/core/Card';
import {XDSSection} from '@xds/core/Section';
import {FunnelIcon, PlusIcon} from '@heroicons/react/24/outline';
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
card: {
width: 600,
height: '100%',
marginTop: 260,
},
});
export default function ToolbarCardHeader() {
return (
<XDSCard xstyle={styles.card}>
<XDSToolbar
label="User list actions"
size="sm"
dividers={['bottom']}
startContent={<XDSHeading level={4}>Card title</XDSHeading>}
endContent={
<>
<XDSButton
label="Filter"
variant="ghost"
icon={<XDSIcon icon={FunnelIcon} />}
isIconOnly
/>
<XDSButton
label="Add user"
icon={<XDSIcon icon={PlusIcon} />}
isIconOnly
/>
</>
}
/>
<XDSSection />
</XDSCard>
);
}
Toolbar — Sizes
tsx
'use client';
import {XDSToolbar} from '@xds/core/Toolbar';
import {XDSButton} from '@xds/core/Button';
import {XDSIcon} from '@xds/core/Icon';
import {XDSHeading} from '@xds/core/Text';
import {XDSStack} from '@xds/core/Layout';
import {XDSCard} from '@xds/core/Card';
import {FunnelIcon, PlusIcon} from '@heroicons/react/24/outline';
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
container: {
width: 600,
},
});
const SIZES = [
{size: 'sm' as const, label: 'Small'},
{size: 'md' as const, label: 'Medium'},
{size: 'lg' as const, label: 'Large'},
];
export default function ToolbarSizes() {
return (
<XDSStack direction="vertical" gap={4} xstyle={styles.container}>
{SIZES.map(({size, label}) => (
<XDSCard key={size}>
<XDSToolbar
label={`${label} toolbar`}
size={size}
dividers={['bottom']}
startContent={<XDSHeading level={4}>{label}</XDSHeading>}
endContent={
<>
<XDSButton
label="Filter"
variant="ghost"
icon={<XDSIcon icon={FunnelIcon} />}
isIconOnly
/>
<XDSButton label="Add" icon={<XDSIcon icon={PlusIcon} />} />
</>
}
/>
</XDSCard>
))}
</XDSStack>
);
}
Toolbar — Tab NavigationA toolbar with tabs in the start slot and an action button at the end. Use as a card or section header when content is split into tabs with a primary action alongside.
tsx
'use client';
import {useState} from 'react';
import {XDSToolbar} from '@xds/core/Toolbar';
import {XDSButton} from '@xds/core/Button';
import {XDSIcon} from '@xds/core/Icon';
import {XDSTabList, XDSTab} from '@xds/core/TabList';
import {XDSCard} from '@xds/core/Card';
import {XDSSection} from '@xds/core/Section';
import {PlusIcon} from '@heroicons/react/24/outline';
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
card: {
width: '100%',
height: '100%',
marginTop: 200,
},
});
export default function ToolbarWithTabs() {
const [tab, setTab] = useState('overview');
return (
<XDSCard xstyle={styles.card}>
<XDSToolbar
label="Section navigation"
dividers={['bottom']}
startContent={
<XDSTabList value={tab} onChange={setTab}>
<XDSTab value="overview" label="Overview" />
<XDSTab value="analytics" label="Analytics" />
<XDSTab value="settings" label="Settings" />
</XDSTabList>
}
endContent={
<XDSButton
label="New item"
icon={<XDSIcon icon={PlusIcon} />}
isIconOnly
/>
}
/>
<XDSSection />
</XDSCard>
);
}
Toolbar — Table FilterA compact toolbar with a search input, filter buttons, and an overflow menu. Use above a data table to let users search, filter, and access view options.
tsx
'use client';
import {XDSToolbar} from '@xds/core/Toolbar';
import {XDSButton} from '@xds/core/Button';
import {XDSIcon} from '@xds/core/Icon';
import {XDSTextInput} from '@xds/core/TextInput';
import {XDSMoreMenu} from '@xds/core/MoreMenu';
import {XDSStack} from '@xds/core/Layout';
import {XDSTable} from '@xds/core/Table';
import * as stylex from '@stylexjs/stylex';
import {
MagnifyingGlassIcon,
ChevronDownIcon,
} from '@heroicons/react/24/outline';
const styles = stylex.create({
container: {
width: 600,
},
});
export default function ToolbarTableFilter() {
return (
<XDSStack direction="vertical" xstyle={styles.container}>
<XDSToolbar
label="Table filters"
size="sm"
dividers={['bottom']}
startContent={
<>
<XDSTextInput
label="Search"
isLabelHidden
placeholder="Search..."
value=""
onChange={() => {}}
startIcon={MagnifyingGlassIcon}
/>
<XDSButton
label="Status"
variant="secondary"
endContent={<XDSIcon icon={ChevronDownIcon} />}
/>
<XDSButton
label="Priority"
variant="secondary"
endContent={<XDSIcon icon={ChevronDownIcon} />}
/>
</>
}
endContent={
<XDSMoreMenu
items={[
{label: 'Compact view'},
{label: 'Comfortable view'},
{label: 'Export CSV'},
]}
/>
}
/>
<XDSTable
idKey="id"
columns={[
{key: 'task', header: 'Task'},
{key: 'status', header: 'Status'},
{key: 'priority', header: 'Priority'},
]}
data={[
{id: '1', task: 'Fix login bug', status: 'Open', priority: 'High'},
{
id: '2',
task: 'Update docs',
status: 'In progress',
priority: 'Medium',
},
{id: '3', task: 'Add unit tests', status: 'Open', priority: 'Low'},
]}
/>
</XDSStack>
);
}

Showcase source

tsx
'use client';
import {XDSToolbar} from '@xds/core/Toolbar';
import {XDSButton} from '@xds/core/Button';
import {XDSIcon} from '@xds/core/Icon';
import {XDSHeading} from '@xds/core/Text';
import {XDSCard} from '@xds/core/Card';
import {XDSSection} from '@xds/core/Section';
import {ArrowLeftIcon} from '@heroicons/react/24/outline';
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
card: {
width: 600,
height: '100%',
marginTop: 260,
},
});
export default function ToolbarThreeSlot() {
return (
<XDSCard xstyle={styles.card}>
<XDSToolbar
label="Document toolbar"
dividers={['bottom']}
startContent={
<XDSButton
label="Back"
variant="ghost"
icon={<XDSIcon icon={ArrowLeftIcon} />}
isIconOnly
/>
}
centerContent={<XDSHeading level={4}>Title</XDSHeading>}
endContent={
<>
<XDSButton label="Discard" variant="secondary" />
<XDSButton label="Save" variant="primary" />
</>
}
/>
<XDSSection />
</XDSCard>
);
}