<!-- Protocore Design System — Toolbar -->
# Toolbar

- **Category:** Navigation (`navigation`)
- **Slug:** `navigation/toolbar`
- **Status:** stable
- **Platforms:** web
- **Import:** `import { Toolbar } from "@protocore/pds";`
- **Docs:** https://pds.protocore.io/components/navigation/toolbar

> Horizontal group of always-visible controls — ghost buttons, chip-like toggle groups, links and hairline separators with roving-tabindex arrow navigation.

## When to use it

Use **Toolbar** for a compact strip of **always-visible** controls acting on the current view or selection — formatting marks, view switches, quick actions above a table or canvas. Everything is on screen and one keyboard journey away.

- Actions grouped under menus (File/Edit/View) belong in a **Menubar**.
- A set of related buttons that share one border rhythm, with no roving/toggle semantics, is a **ButtonGroup**.
- A single exclusive mode switch reads best as a **SegmentedControl**.
- Faceted filtering of a list is a **FilterBar**.

## Examples

### Basics

Compose `Toolbar.Root` with `Toolbar.Button`s, `Toolbar.Separator`s and a `Toolbar.Link`. The row is a single Tab stop; arrow keys move between controls (roving tabindex). Always give the toolbar an `aria-label`.

```tsx
import { Toolbar } from "@protocore/pds";

export default function ToolbarBasics() {
  return (
    <Toolbar.Root aria-label="Content actions">
      <Toolbar.Button>New</Toolbar.Button>
      <Toolbar.Button>Duplicate</Toolbar.Button>
      <Toolbar.Separator />
      <Toolbar.Button>Preview</Toolbar.Button>
      <Toolbar.Button>Publish</Toolbar.Button>
      <Toolbar.Separator />
      <Toolbar.Link href="#docs">Docs</Toolbar.Link>
    </Toolbar.Root>
  );
}
```

### Toggle groups

`Toolbar.ToggleGroup` holds `Toolbar.ToggleItem`s that invert to the inked fill when pressed — chip-like segmented controls. Use `type="single"` for a mutually-exclusive choice (like alignment) or `type="multiple"` for independent marks (bold / italic).

```tsx
import * as React from "react";
import { Toolbar } from "@protocore/pds";

export default function ToolbarToggles() {
  const [align, setAlign] = React.useState("left");
  const [marks, setMarks] = React.useState<string[]>(["bold"]);

  return (
    <Toolbar.Root aria-label="Text formatting">
      <Toolbar.ToggleGroup
        type="multiple"
        value={marks}
        onValueChange={setMarks}
        aria-label="Text marks"
      >
        <Toolbar.ToggleItem value="bold">Bold</Toolbar.ToggleItem>
        <Toolbar.ToggleItem value="italic">Italic</Toolbar.ToggleItem>
        <Toolbar.ToggleItem value="code">Code</Toolbar.ToggleItem>
      </Toolbar.ToggleGroup>

      <Toolbar.Separator />

      <Toolbar.ToggleGroup
        type="single"
        value={align}
        onValueChange={(v) => v && setAlign(v)}
        aria-label="Alignment"
      >
        <Toolbar.ToggleItem value="left">Left</Toolbar.ToggleItem>
        <Toolbar.ToggleItem value="center">Center</Toolbar.ToggleItem>
        <Toolbar.ToggleItem value="right">Right</Toolbar.ToggleItem>
      </Toolbar.ToggleGroup>
    </Toolbar.Root>
  );
}
```

## Do & don't

**Do**

- Give the toolbar an `aria-label` describing what it acts on.
- Use ToggleGroup `type="single"` for exclusive modes, `type="multiple"` for independent marks.
- Separate unrelated clusters of controls with `Toolbar.Separator`.
- Give icon-only buttons an `aria-label` so their action is announced.

**Don't**

- Don't hide actions behind menus here — that's what a Menubar is for.
- Don't mix a toolbar's roving-tabindex model with nested independent tab stops.
- Don't use a toggle item for a one-shot action — that's a Button.
- Don't overload one toolbar with dozens of controls; group and separate them.

## Accessibility

**Keyboard**

| Keys | Action |
| --- | --- |
| `Tab` | Move focus into the toolbar (one stop for the whole strip). |
| `Arrow Left / Right` | Move between controls within the toolbar. |
| `Home / End` | Jump to the first / last control. |
| `Enter / Space` | Activate the focused button or toggle. |

**Notes**

- Built on Radix Toolbar — the root is a `role="toolbar"` with roving tabindex, so the whole strip is a single Tab stop and arrows move within it.
- ToggleItems expose their pressed state to assistive tech (single groups as radios, multiple groups as pressed toggles); the chip inversion is the matching visual signal.
- Buttons follow the ghost recipe and icon-only controls require an `aria-label`; links render as real anchors and follow on Enter.

## Related

`menubar`, `button-group`, `segmented-control`, `filter-bar`

---

© Protocore. All rights reserved. Use of the Protocore Design System requires prior written authorization from Protocore (contact@protocore.io). These machine-readable materials must not be ingested into ML-training datasets or derivative design systems. See https://pds.protocore.io/legal/
