# Toolbar (/ui/components/react/toolbar)



## Usage [#usage]

```tsx
import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator, ToolbarLink } from '@appica/ui-react/toolbar'
import { Button } from '@appica/ui-react/button'
```

```tsx
<Toolbar aria-label="Formatting">
  <ToolbarGroup aria-label="Text style">
    <ToolbarButton render={<Button variant="ghost">Bold</Button>} />
    <ToolbarButton render={<Button variant="ghost">Italic</Button>} />
  </ToolbarGroup>
  <ToolbarSeparator />
  <ToolbarLink href="#help">Help</ToolbarLink>
</Toolbar>
```

`Toolbar` is a `role="toolbar"` strip with a roving tabindex: the toolbar holds a single tab stop, and the arrow keys move focus between its items (with `Home`/`End` jumping to the ends). This keeps the whole group to one stop in the page's tab order while still letting keyboard users reach every control. Set `orientation="vertical"` to stack items and switch the arrow keys to the vertical axis; `disabled` disables every item at once.

The items are composed, not bespoke: `ToolbarButton` renders any button you pass to `render` — most often a ghost [`Button`](/ui/components/react/button) — so the toolbar inherits your existing styles while the toolbar wiring (focus order, `disabled`) is added on top. `ToolbarSeparator` always renders **perpendicular** to the toolbar (a horizontal toolbar gets vertical dividers, and vice-versa), so you never set its orientation by hand. Give the toolbar an accessible name with `aria-label`, and name each `ToolbarGroup` the same way.

A toolbar never reflows: its items keep their size, and when there isn't room the bar caps to the available width and scrolls along its axis instead (the scrollbar is hidden — the clipped edge already hints there's more). That's built in, so you don't wrap it yourself.

## Examples [#examples]

### Default [#default]

A table toolbar that mixes the part types: a `ToolbarInput` search box (rendered as an [`Input`](/ui/components/react/input)), a `ToolbarGroup` holding a ghost-[`Button`](/ui/components/react/button) `Filter` action, and an `Export` `ToolbarLink`. Each lands in the same roving-focus order, so one **Tab** reaches the strip and the arrow keys walk from the search box through to the link. On a narrow screen the bar scrolls sideways rather than reflowing — no wrapper needed.

```tsx
import { Search, Filter, SortAscending, Download } from '@appica/icons-react'
import { Button, buttonVariants } from '@appica/ui-react/button'
import { Input } from '@appica/ui-react/input'
import {
  Toolbar,
  ToolbarButton,
  ToolbarGroup,
  ToolbarInput,
  ToolbarLink,
  ToolbarSeparator,
} from '@appica/ui-react/toolbar'

export default function ToolbarDefault() {
  return (
    <Toolbar aria-label="Table actions">
      <ToolbarInput
        className="w-44"
        render={<Input startSlot={<Search />} placeholder="Search tasks…" aria-label="Search tasks" />}
      />

      <ToolbarGroup aria-label="Refine">
        <ToolbarButton
          render={
            <Button variant="ghost">
              <Filter data-icon="start" />
              Filter
            </Button>
          }
        />
      </ToolbarGroup>

      <ToolbarSeparator />

      <ToolbarLink href="#export" className={buttonVariants({ variant: 'ghost' })}>
        <Download data-icon="start" />
        Export
      </ToolbarLink>
    </Toolbar>
  )
}
```

### With a toggle group [#with-a-toggle-group]

A rich-text editing toolbar. The undo/redo `ToolbarGroup` and a font [`Select`](/ui/components/react/select) sit beside a true single-select alignment [`ToggleGroup`](/ui/components/react/toggle-group) — built by wrapping each `ToolbarButton render={<Toggle …/>}` in a `ToggleGroup`, so the toggles share one pressed value (picking an alignment releases the previous one) while still taking part in the toolbar's roving focus. The selection state is the group's own — no extra wiring.

```tsx
'use client'

import { ArrowBackUp, ArrowForwardUp, AlignLeft, AlignCenter, AlignRight, Typography } from '@appica/icons-react'
import { Button } from '@appica/ui-react/button'
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@appica/ui-react/select'
import { Toggle } from '@appica/ui-react/toggle'
import { ToggleGroup } from '@appica/ui-react/toggle-group'
import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator } from '@appica/ui-react/toolbar'

export default function ToolbarWithToggles() {
  return (
    <Toolbar aria-label="Text formatting">
      <ToolbarGroup aria-label="History">
        <ToolbarButton
          render={
            <Button variant="ghost" size="icon-md" aria-label="Undo">
              <ArrowBackUp />
            </Button>
          }
        />
        <ToolbarButton
          render={
            <Button variant="ghost" size="icon-md" aria-label="Redo">
              <ArrowForwardUp />
            </Button>
          }
        />
      </ToolbarGroup>

      <ToolbarSeparator />

      <Select defaultValue="Inter" alignItemWithTrigger={false}>
        <ToolbarButton
          className="w-36"
          render={
            <SelectTrigger startSlot={<Typography />} aria-label="Font">
              <SelectValue />
            </SelectTrigger>
          }
        />
        <SelectContent>
          <SelectItem value="Geist">Geist</SelectItem>
          <SelectItem value="Inter">Inter</SelectItem>
          <SelectItem value="Georgia">Figrtree</SelectItem>
          <SelectItem value="Urbanist">Urbanist</SelectItem>
        </SelectContent>
      </Select>

      <ToolbarSeparator />

      <ToggleGroup defaultValue={['left']} aria-label="Alignment">
        <ToolbarButton
          render={
            <Toggle
              value="left"
              aria-label="Align left"
              render={
                <Button variant="ghost" size="icon-md">
                  <AlignLeft />
                </Button>
              }
            />
          }
        />
        <ToolbarButton
          render={
            <Toggle
              value="center"
              aria-label="Align center"
              render={
                <Button variant="ghost" size="icon-md">
                  <AlignCenter />
                </Button>
              }
            />
          }
        />
        <ToolbarButton
          render={
            <Toggle
              value="right"
              aria-label="Align right"
              render={
                <Button variant="ghost" size="icon-md">
                  <AlignRight />
                </Button>
              }
            />
          }
        />
      </ToggleGroup>
    </Toolbar>
  )
}
```

### Vertical orientation [#vertical-orientation]

Set `orientation="vertical"` to stack the items into a column — here a formatting group and a clipboard group. The arrow keys follow the vertical axis and the `ToolbarSeparator` between the groups flips to a horizontal divider automatically.

```tsx
import { Bold, Italic, Underline, Copy, Scissors } from '@appica/icons-react'
import { Button } from '@appica/ui-react/button'
import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator } from '@appica/ui-react/toolbar'

export default function ToolbarVertical() {
  return (
    <Toolbar aria-label="Formatting" orientation="vertical">
      <ToolbarGroup aria-label="Text style">
        <ToolbarButton
          render={
            <Button variant="ghost" size="icon-md" aria-label="Bold">
              <Bold />
            </Button>
          }
        />
        <ToolbarButton
          render={
            <Button variant="ghost" size="icon-md" aria-label="Italic">
              <Italic />
            </Button>
          }
        />
        <ToolbarButton
          render={
            <Button variant="ghost" size="icon-md" aria-label="Underline">
              <Underline />
            </Button>
          }
        />
      </ToolbarGroup>

      <ToolbarSeparator />

      <ToolbarGroup aria-label="Clipboard">
        <ToolbarButton
          render={
            <Button variant="ghost" size="icon-md" aria-label="Copy">
              <Copy />
            </Button>
          }
        />
        <ToolbarButton
          render={
            <Button variant="ghost" size="icon-md" aria-label="Cut">
              <Scissors />
            </Button>
          }
        />
      </ToolbarGroup>
    </Toolbar>
  )
}
```

## RTL [#rtl]

Every Appica UI component supports right-to-left layouts out of the box. Set the `dir` attribute on a container (commonly your `<html>` element) so CSS logical properties resolve correctly, and wrap your tree in `DirectionProvider` so direction-aware behavior — roving focus, popup placement, and the like — follows the same direction.

```tsx
import { DirectionProvider } from '@appica/ui-react/providers/direction-provider'

export default function RootLayout({ children }) {
  return (
    <html lang="ar" dir="rtl">
      <body>
        <DirectionProvider dir="rtl">{children}</DirectionProvider>
      </body>
    </html>
  )
}
```

Items and groups align to the start edge and the arrow-key focus order follows the resolved direction. For setup details and caveats, see the [RTL guide](/ui/docs/react/rtl).

<RtlPreview component="toolbar" />

## API reference [#api-reference]

`Toolbar` wraps [Base UI's Toolbar](https://base-ui.com/react/components/toolbar). Each part forwards every remaining prop to the matching Base UI primitive, so anything it accepts works here — the tables below list the most common props.

### Toolbar [#toolbar]

The root strip. Renders a `role="toolbar"` `<div>` and exposes `data-orientation`.

| Prop          | <ColMinWidth width="180">Type</ColMinWidth>                   | Default        | <ColMinWidth width="220">Description</ColMinWidth>                      |
| ------------- | ------------------------------------------------------------- | -------------- | ----------------------------------------------------------------------- |
| `orientation` | <Code>'horizontal' \| 'vertical'</Code>                       | `'horizontal'` | Layout axis; also the axis the arrow keys move focus along.             |
| `disabled`    | `boolean`                                                     | `false`        | Disable every item in the toolbar at once.                              |
| `loopFocus`   | `boolean`                                                     | `true`         | Wrap focus to the other end when arrowing past the first or last item.  |
| `render`      | <Code>ReactElement \| ((props, state) => ReactElement)</Code> | —              | Replace the `<div>`, or compose it with another component.              |
| `className`   | <Code>string \| ((state) => string)</Code>                    | —              | Extra classes, merged via `tailwind-merge`. May be a function of state. |

Also forwards `ref` and every remaining native `<div>` attribute.

### ToolbarButton [#toolbarbutton]

A toolbar item button, usually composed with a [`Button`](/ui/components/react/button) via `render`.

| Prop                    | <ColMinWidth width="180">Type</ColMinWidth>                   | Default | <ColMinWidth width="220">Description</ColMinWidth>                 |
| ----------------------- | ------------------------------------------------------------- | ------- | ------------------------------------------------------------------ |
| `disabled`              | `boolean`                                                     | `false` | Disable just this item.                                            |
| `focusableWhenDisabled` | `boolean`                                                     | `true`  | Keep a disabled item reachable by the roving focus.                |
| `render`                | <Code>ReactElement \| ((props, state) => ReactElement)</Code> | —       | Render-as: pass your own button (e.g. `<Button variant="ghost">`). |
| `className`             | `string`                                                      | —       | Extra classes, merged via `tailwind-merge`.                        |

### ToolbarLink [#toolbarlink]

A link item (`<a href>`, `role="link"`) that joins the roving focus order.

| Prop        | <ColMinWidth width="180">Type</ColMinWidth>                   | Default | <ColMinWidth width="220">Description</ColMinWidth>            |
| ----------- | ------------------------------------------------------------- | ------- | ------------------------------------------------------------- |
| `href`      | `string`                                                      | —       | The link target.                                              |
| `render`    | <Code>ReactElement \| ((props, state) => ReactElement)</Code> | —       | Render-as: compose with a framework `<Link>` or other anchor. |
| `className` | `string`                                                      | —       | Extra classes, merged via `tailwind-merge`.                   |

### ToolbarInput [#toolbarinput]

An input item that lives in the toolbar's focus order — a search box or inline value field.

| Prop                    | <ColMinWidth width="180">Type</ColMinWidth>                   | Default | <ColMinWidth width="220">Description</ColMinWidth>                |
| ----------------------- | ------------------------------------------------------------- | ------- | ----------------------------------------------------------------- |
| `disabled`              | `boolean`                                                     | `false` | Disable just this item.                                           |
| `focusableWhenDisabled` | `boolean`                                                     | `true`  | Keep a disabled input reachable by the roving focus.              |
| `render`                | <Code>ReactElement \| ((props, state) => ReactElement)</Code> | —       | Render-as: compose with an [`Input`](/ui/components/react/input). |
| `className`             | `string`                                                      | —       | Extra classes, merged via `tailwind-merge`.                       |

### ToolbarGroup [#toolbargroup]

Groups related items under a single `role="group"`. Lay out as a flex row (or column under `data-orientation=vertical`).

| Prop         | <ColMinWidth width="180">Type</ColMinWidth> | Default | <ColMinWidth width="220">Description</ColMinWidth> |
| ------------ | ------------------------------------------- | ------- | -------------------------------------------------- |
| `disabled`   | `boolean`                                   | `false` | Disable every item in the group.                   |
| `aria-label` | `string`                                    | —       | Names the group for assistive tech.                |
| `className`  | <Code>string \| ((state) => string)</Code>  | —       | Extra classes, merged via `tailwind-merge`.        |

### ToolbarSeparator [#toolbarseparator]

A divider rendered **perpendicular** to the toolbar — vertical inside a horizontal toolbar, horizontal inside a vertical one.

| Prop          | <ColMinWidth width="180">Type</ColMinWidth> | Default                 | <ColMinWidth width="220">Description</ColMinWidth>                    |
| ------------- | ------------------------------------------- | ----------------------- | --------------------------------------------------------------------- |
| `orientation` | <Code>'horizontal' \| 'vertical'</Code>     | opposite of the toolbar | Override the divider axis. Rarely needed — the default flips for you. |
| `className`   | <Code>string \| ((state) => string)</Code>  | —                       | Extra classes, merged via `tailwind-merge`.                           |

## Accessibility [#accessibility]

* The root renders `role="toolbar"`; give it an accessible name with `aria-label` (or `aria-labelledby`).
* Focus uses a **roving tabindex** — the toolbar is a single tab stop, and the arrow keys move focus between items along the toolbar's orientation.
* **Home** / **End** jump focus to the first and last items.
* Name each `ToolbarGroup` with `aria-label` so its `role="group"` is announced.
* `disabled` on the toolbar (or a group) disables its items; items stay focusable when disabled (`focusableWhenDisabled`) so keyboard users can still reach and read them.
