Toolbar
General toolbar layout component for headings, counts, grouped controls, actions, and separators.
Overview
Toolbar provides consistent shell spacing for dense UI surfaces without
owning the controls inside it. Compose it with Button, Input,
SearchExpand, ToggleGroup, Menu, Breadcrumb, and other components.
size scales toolbar-owned gaps, separators, title text, count text, and the
title trigger. Pass the same size to the controls you compose inside the
toolbar so the full row follows one density.
Use Toolbar.TitleTrigger next to Toolbar.Title for a title-adjacent
selection label, such as Attach Files. It moves from muted text to foreground
text on hover and while its menu is open.
Use Toolbar.Breadcrumb when the heading becomes a path. It styles the
primitive breadcrumb slots for toolbar heading scale while leaving links,
overflow menus, route state, and folder data with the consumer. Use text
separators such as / for path-like toolbar headings. Collapse states are
explicit composition: render BreadcrumbIcon, BreadcrumbLabel,
BreadcrumbOverflowMenu, and tooltips from consumer-owned path data.
Usage
import { Toolbar } from "@tilt-legal/cubitt-components/toolbar";
<Toolbar size="md">
<Toolbar.Heading>
<Toolbar.Title>Files</Toolbar.Title>
<Toolbar.Count>18</Toolbar.Count>
</Toolbar.Heading>
<Toolbar.Actions>{actions}</Toolbar.Actions>
</Toolbar>;Examples
Sizes
import { Button } from "@tilt-legal/cubitt-components/button";
import {
ToggleGroup,
ToggleGroupItem,
} from "@tilt-legal/cubitt-components/toggle-group";
import { Toolbar } from "@tilt-legal/cubitt-components/toolbar";
import { Grid, Menu, SortArrows } from "@tilt-legal/cubitt-icons/ui/outline";
{(["sm", "md", "lg"] as const).map((size) => (
<Toolbar key={size} size={size}>
<Toolbar.Heading>
<Toolbar.Title>{size.toUpperCase()} toolbar</Toolbar.Title>
<Toolbar.Count>12</Toolbar.Count>
</Toolbar.Heading>
<Toolbar.Actions>
<Button aria-label="Sort files" mode="icon" size={size} variant="secondary">
<SortArrows />
</Button>
<ToggleGroup
aria-label="View options"
groupVariant="segmented"
multiple={false}
size={size}
value={view}
onValueChange={setView}
>
<ToggleGroupItem aria-label="Grid view" mode="icon" value="grid">
<Grid />
</ToggleGroupItem>
<ToggleGroupItem aria-label="List view" mode="icon" value="list">
<Menu />
</ToggleGroupItem>
</ToggleGroup>
<Toolbar.Separator />
<Button size={size}>Action</Button>
</Toolbar.Actions>
</Toolbar>
))}With Search
import { Button } from "@tilt-legal/cubitt-components/button";
import { Input } from "@tilt-legal/cubitt-components/input";
import { SearchExpand } from "@tilt-legal/cubitt-components/search-expand";
import {
ToggleGroup,
ToggleGroupItem,
} from "@tilt-legal/cubitt-components/toggle-group";
import { Toolbar } from "@tilt-legal/cubitt-components/toolbar";
import { Grid, Menu, Plus, Xmark } from "@tilt-legal/cubitt-icons/ui/outline";
<Toolbar size="md">
<Toolbar.Heading>
<Toolbar.Title>Documents</Toolbar.Title>
<Toolbar.Count>42</Toolbar.Count>
</Toolbar.Heading>
<Toolbar.Actions>
<SearchExpand collapseOnBlurWhenEmpty size="md">
<Input
aria-label="Search files"
placeholder="Search files"
size="md"
value={query}
onChange={(event) => setQuery(event.currentTarget.value)}
/>
<Button
className="-me-2"
disabled={!query}
mode="icon"
onClick={() => setQuery("")}
size="md"
type="button"
variant="link"
>
{query ? <Xmark /> : null}
</Button>
</SearchExpand>
<ToggleGroup
aria-label="View options"
groupVariant="segmented"
multiple={false}
size="md"
value={view}
onValueChange={setView}
>
<ToggleGroupItem aria-label="Grid view" mode="icon" value="grid">
<Grid />
</ToggleGroupItem>
<ToggleGroupItem aria-label="List view" mode="icon" value="list">
<Menu />
</ToggleGroupItem>
</ToggleGroup>
<Toolbar.Separator />
<Button size="md" variant="secondary">
<Plus />
Add
</Button>
</Toolbar.Actions>
</Toolbar>Breadcrumb
import {
BreadcrumbIcon,
BreadcrumbItem,
BreadcrumbLabel,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbOverflowItem,
BreadcrumbOverflowMenu,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@tilt-legal/cubitt-components/breadcrumb";
import { Button } from "@tilt-legal/cubitt-components/button";
import { Toolbar } from "@tilt-legal/cubitt-components/toolbar";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@tilt-legal/cubitt-components/tooltip";
import { FilesFolderIcon } from "@tilt-legal/cubitt-components/files";
const hiddenFolders = [
{ id: "matter", label: "Matter" },
{ id: "disclosure", label: "Disclosure" },
];
const widthClassName = "w-[28rem]";
<Toolbar>
<Toolbar.Heading className={widthClassName}>
<Toolbar.Breadcrumb className="@container w-full">
<BreadcrumbList>
<BreadcrumbItem className="shrink-0">
<BreadcrumbLink href="/">
<BreadcrumbLabel className="shrink-0">Files</BreadcrumbLabel>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator>/</BreadcrumbSeparator>
<BreadcrumbItem className="hidden @max-[24rem]:inline-flex">
<BreadcrumbOverflowMenu>
{hiddenFolders.map((folder) => (
<BreadcrumbOverflowItem key={folder.id}>
<FilesFolderIcon />
{folder.label}
</BreadcrumbOverflowItem>
))}
</BreadcrumbOverflowMenu>
</BreadcrumbItem>
<BreadcrumbSeparator className="hidden @max-[24rem]:inline-flex">
/
</BreadcrumbSeparator>
<BreadcrumbItem className="shrink-0 @max-[24rem]:hidden">
<Tooltip delay={400}>
<TooltipTrigger
render={
<BreadcrumbLink href="/">
<BreadcrumbIcon>
<FilesFolderIcon />
</BreadcrumbIcon>
<BreadcrumbLabel className="shrink-0 @max-[34rem]:sr-only">
Matter
</BreadcrumbLabel>
</BreadcrumbLink>
}
/>
<TooltipContent side="bottom">Matter</TooltipContent>
</Tooltip>
</BreadcrumbItem>
<BreadcrumbSeparator className="@max-[24rem]:hidden">/</BreadcrumbSeparator>
<BreadcrumbItem className="shrink-0 @max-[24rem]:hidden">
<BreadcrumbLink href="/">
<BreadcrumbIcon>
<FilesFolderIcon />
</BreadcrumbIcon>
<BreadcrumbLabel className="shrink-0">Disclosure</BreadcrumbLabel>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator className="@max-[24rem]:hidden">/</BreadcrumbSeparator>
<BreadcrumbItem className="shrink-0">
<BreadcrumbPage>
<BreadcrumbIcon>
<FilesFolderIcon />
</BreadcrumbIcon>
<BreadcrumbLabel className="shrink-0">Closing Set</BreadcrumbLabel>
</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Toolbar.Breadcrumb>
</Toolbar.Heading>
<Toolbar.Actions>
<Button>Upload</Button>
</Toolbar.Actions>
</Toolbar>Title Trigger
import { Button } from "@tilt-legal/cubitt-components/button";
import {
Menu,
MenuContent,
MenuRadioGroup,
MenuRadioItem,
MenuTrigger,
} from "@tilt-legal/cubitt-components/menu";
import { Toolbar } from "@tilt-legal/cubitt-components/toolbar";
const activeLabel =
panels.find((panel) => panel.id === activePanel)?.label ?? "";
<Toolbar>
<Toolbar.Heading>
<Toolbar.Title>Attach</Toolbar.Title>
<Menu>
<MenuTrigger
render={<Toolbar.TitleTrigger>{activeLabel}</Toolbar.TitleTrigger>}
/>
<MenuContent align="start">
<MenuRadioGroup onValueChange={setActivePanel} value={activePanel}>
{panels.map((panel) => (
<MenuRadioItem closeOnClick key={panel.id} value={panel.id}>
{panel.label}
</MenuRadioItem>
))}
</MenuRadioGroup>
</MenuContent>
</Menu>
</Toolbar.Heading>
<Toolbar.Actions>
<Button>Attach</Button>
</Toolbar.Actions>
</Toolbar>API Reference
Toolbar
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "md" | "lg" | "md" | Scales toolbar-owned spacing, separator height, title text, count text, and title trigger text. Pass matching sizes to composed controls. |
wrap | boolean | false | Allows toolbar contents to wrap when horizontal space is constrained. |
className | string | - | Overrides or extends root toolbar styles. |
children | ReactNode | - | Toolbar content. |
Also accepts standard div props.
Toolbar.Heading
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Overrides or extends the heading region. |
children | ReactNode | - | Usually Toolbar.Title, Toolbar.TitleTrigger, and Toolbar.Count. |
Also accepts standard div props.
Toolbar.Title
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Overrides or extends title text styles, including size when needed. |
children | ReactNode | - | Title content. |
Also accepts standard div props.
Toolbar.Breadcrumb
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Overrides or extends toolbar breadcrumb styles. |
children | ReactNode | - | Primitive breadcrumb composition, usually BreadcrumbList and its child slots. |
Also accepts primitive Breadcrumb props.
Toolbar.TitleTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
showChevron | boolean | true | Shows the trailing chevron. |
chevron | ReactNode | <ChevronDown /> | Custom trailing indicator. |
className | string | - | Overrides or extends the title trigger styles. |
children | ReactNode | - | Active adjacent label. |
Also accepts Button props.
Toolbar.Count
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Overrides or extends count text styles. |
children | ReactNode | - | Count content. |
Also accepts standard span props.
Toolbar.Group And Toolbar.Actions
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Overrides or extends the control group. |
children | ReactNode | - | Grouped controls. |
Both accept standard div props.
Toolbar.Spacer
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Overrides or extends the flexible spacer. |
Also accepts standard div props.
Toolbar.Separator
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | "horizontal" | "vertical" | "vertical" | Separator direction. Vertical separators get toolbar-sized heights. |
className | string | - | Overrides or extends separator styles. |
Also accepts primitive Separator props.