

<Preview name="ToolbarDefaultExample" />

## Overview [#overview]

`Toolbar` provides consistent shell spacing for dense UI rows without owning the
surfaces of 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 composed controls when the whole row should
follow one density.

`Toolbar.TitleTrigger` is an unstyled `Button` for title-adjacent menu labels.
It stays surface-free and only handles text hover/open color.

`Toolbar.Separator` renders the Cubitt `Separator` component with toolbar-sized
vertical heights, so separator color remains context-aware.

`Toolbar.Breadcrumb` adapts breadcrumb slots for toolbar heading scale while
leaving links, menus, route state, and path data with the consumer.

## Usage [#usage]

```tsx
import { Toolbar } from "@tilt-legal/cubitt-components/toolbar";
```

```tsx
<Toolbar size="md">
  <Toolbar.Heading>
    <Toolbar.Title>Files</Toolbar.Title>
    <Toolbar.Count>18</Toolbar.Count>
  </Toolbar.Heading>
  <Toolbar.Actions>{actions}</Toolbar.Actions>
</Toolbar>
```

## Examples [#examples]

### Default [#default]

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="ToolbarDefaultExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    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,
      Plus,
      SortArrows,
    } from "@tilt-legal/cubitt-icons/ui/outline";

    export default function Example() {
      return (
        <Toolbar size="md">
          <Toolbar.Heading>
            <Toolbar.Title>Files</Toolbar.Title>
            <Toolbar.Count>18</Toolbar.Count>
          </Toolbar.Heading>
          <Toolbar.Actions>
            <Button
              aria-label="Sort files"
              mode="icon"
              size="md"
              variant="secondary"
            >
              <SortArrows />
            </Button>
            <ToggleGroup
              aria-label="View options"
              defaultValue="list"
              groupVariant="segmented"
              size="md"
            >
              <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">
              <Plus />
              Upload
            </Button>
          </Toolbar.Actions>
        </Toolbar>
      );
    }
    ```
  </Tab>
</Tabs>

### Sizes [#sizes]

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="ToolbarSizesExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    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";

    export default function Example() {
      return (
        <div className="grid w-full gap-4">
          {(["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"
                  defaultValue="list"
                  groupVariant="segmented"
                  size={size}
                >
                  <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>
          ))}
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

### With Search [#with-search]

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="ToolbarWithSearchExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { useState } from "react";
    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";

    export default function Example() {
      const [query, setQuery] = useState("");

      return (
        <Toolbar size="md">
          <Toolbar.Heading>
            <Toolbar.Title>Documents</Toolbar.Title>
            <Toolbar.Count>42</Toolbar.Count>
          </Toolbar.Heading>
          <Toolbar.Actions>
            <SearchExpand collapseOnBlurWhenEmpty>
              <Input
                aria-label="Search files"
                onChange={(event) => setQuery(event.currentTarget.value)}
                placeholder="Search files"
                size="md"
                value={query}
              />
              <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"
              defaultValue="list"
              groupVariant="segmented"
              size="md"
            >
              <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>
      );
    }
    ```
  </Tab>
</Tabs>

### Breadcrumb [#breadcrumb]

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="ToolbarBreadcrumbExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    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 { FilesFolderIcon } from "@tilt-legal/cubitt-components/files";
    import {
      Tooltip,
      TooltipContent,
      TooltipTrigger,
    } from "@tilt-legal/cubitt-components/tooltip";
    import { Toolbar } from "@tilt-legal/cubitt-components/toolbar";
    import { Plus, SortArrows } from "@tilt-legal/cubitt-icons/ui/outline";

    export default function Example() {
      const hiddenFolders = [
        { id: "matter", label: "Matter" },
        { id: "disclosure", label: "Disclosure" },
      ];

      return (
        <Toolbar className="max-w-4xl" size="md">
          <Toolbar.Heading className="w-[28rem]">
            <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
              aria-label="Sort files"
              mode="icon"
              size="md"
              variant="secondary"
            >
              <SortArrows />
            </Button>
            <Button size="md">
              <Plus />
              Upload
            </Button>
          </Toolbar.Actions>
        </Toolbar>
      );
    }
    ```
  </Tab>
</Tabs>

### Title Trigger [#title-trigger]

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="ToolbarTitleTriggerExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { useState } from "react";
    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";
    import { Dots } from "@tilt-legal/cubitt-icons/ui/outline";

    export default function Example() {
      const [activePanel, setActivePanel] = useState("files");
      const panels = [
        { id: "files", label: "Files" },
        { id: "instructions", label: "Instructions" },
        { id: "links", label: "Links" },
      ];
      const activeLabel =
        panels.find((panel) => panel.id === activePanel)?.label ?? "";

      return (
        <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.Group>
            <Button aria-label="More actions" mode="icon" variant="secondary">
              <Dots />
            </Button>
            <Button>Attach</Button>
          </Toolbar.Group>
        </Toolbar>
      );
    }
    ```
  </Tab>
</Tabs>

## API Reference [#api-reference]

### Toolbar [#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 [#toolbarheading]

| 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 [#toolbartitle]

| 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 [#toolbarbreadcrumb]

| Prop        | Type        | Default | Description                                                                     |
| ----------- | ----------- | ------- | ------------------------------------------------------------------------------- |
| `className` | `string`    | -       | Overrides or extends toolbar breadcrumb layout and scale styles.                |
| `children`  | `ReactNode` | -       | Primitive breadcrumb composition, usually `BreadcrumbList` and its child slots. |

Also accepts primitive `Breadcrumb` props.

### Toolbar.TitleTrigger [#toolbartitletrigger]

| 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 text styles. |
| `children`    | `ReactNode` | -                 | Active adjacent label.                              |

Also accepts `Button` props. The trigger uses Button's `unstyled` mode internally.

### Toolbar.Count [#toolbarcount]

| 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 [#toolbargroup-and-toolbaractions]

| Prop        | Type        | Default | Description                             |
| ----------- | ----------- | ------- | --------------------------------------- |
| `className` | `string`    | -       | Overrides or extends the control group. |
| `children`  | `ReactNode` | -       | Grouped controls.                       |

Both accept standard `div` props.

### Toolbar.Spacer [#toolbarspacer]

| Prop        | Type     | Default | Description                               |
| ----------- | -------- | ------- | ----------------------------------------- |
| `className` | `string` | -       | Overrides or extends the flexible spacer. |

Also accepts standard `div` props.

### Toolbar.Separator [#toolbarseparator]

| 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 Cubitt `Separator` props.
