# Toolbar

Use `ui-toolbar` for command rows, editor headers, file actions, and other compact action clusters. Keep the highest-frequency actions visible and separate unrelated groups clearly.

## Import
```ts
import { ToolbarComponent, type ToolbarItem, type ToolbarGroup } from 'ui';
```

## Basic action row
```ts
import { Component } from '@angular/core';
import { ToolbarComponent, type ToolbarItem } from 'ui';

@Component({
  selector: 'app-toolbar-basic-demo',
  standalone: true,
  imports: [ToolbarComponent],
  template: `
    <div
      style="width:100%;max-width:34rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <ui-toolbar [items]="items" />
    </div>
  `,
})
export class ToolbarBasicDemoComponent {
  protected readonly items: ToolbarItem[] = [
    { id: 'new', label: 'New', icon: 'document_add', tooltip: 'New' },
    { id: 'open', label: 'Open', icon: 'folder_open', tooltip: 'Open' },
    { id: 'save', label: 'Save', icon: 'save', tooltip: 'Save' },
    { id: 'share', label: 'Share', icon: 'share', tooltip: 'Share' },
  ];
}
```

## Grouped actions
```ts
import { Component } from '@angular/core';
import { ToolbarComponent, type ToolbarGroup } from 'ui';

@Component({
  selector: 'app-toolbar-groups-demo',
  standalone: true,
  imports: [ToolbarComponent],
  template: `
    <div
      style="width:100%;max-width:42rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <ui-toolbar [groups]="groups" />
    </div>
  `,
})
export class ToolbarGroupsDemoComponent {
  protected readonly groups: ToolbarGroup[] = [
    {
      id: 'clipboard',
      items: [
        { id: 'cut', icon: 'cut', tooltip: 'Cut' },
        { id: 'copy', icon: 'copy', tooltip: 'Copy' },
        { id: 'paste', icon: 'clipboard_paste', tooltip: 'Paste' },
      ],
    },
    {
      id: 'format',
      items: [
        { id: 'bold', icon: 'text_bold', tooltip: 'Bold', type: 'toggle', selected: true },
        { id: 'italic', icon: 'text_italic', tooltip: 'Italic', type: 'toggle' },
        { id: 'underline', icon: 'text_underline', tooltip: 'Underline', type: 'toggle' },
      ],
    },
    {
      id: 'insert',
      items: [
        { id: 'link', icon: 'link', tooltip: 'Insert link' },
        { id: 'image', icon: 'image', tooltip: 'Insert image' },
      ],
    },
  ];
}
```

## Size and orientation
```ts
import { Component } from '@angular/core';
import { ToolbarComponent, type ToolbarItem } from 'ui';

@Component({
  selector: 'app-toolbar-sizes-orientation-demo',
  standalone: true,
  imports: [ToolbarComponent],
  template: `
    <div
      style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%;max-width:52rem"
    >
      <div
        style="flex:1 1 18rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <p
          style="margin:0 0 0.75rem;font-size:0.875rem;font-weight:600;color:var(--color-neutral-foreground2-rest)"
        >
          Small horizontal
        </p>
        <ui-toolbar [items]="items" size="small" />
      </div>

      <div
        style="flex:0 0 auto;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <p
          style="margin:0 0 0.75rem;font-size:0.875rem;font-weight:600;color:var(--color-neutral-foreground2-rest)"
        >
          Large vertical
        </p>
        <ui-toolbar [items]="items" size="large" orientation="vertical" />
      </div>
    </div>
  `,
})
export class ToolbarSizesOrientationDemoComponent {
  protected readonly items: ToolbarItem[] = [
    { id: 'undo', icon: 'arrow_undo', tooltip: 'Undo' },
    { id: 'redo', icon: 'arrow_redo', tooltip: 'Redo' },
    { id: 'comments', icon: 'comment', tooltip: 'Comments' },
    { id: 'history', icon: 'history', tooltip: 'History' },
  ];
}
```

## Split actions
```ts
import { Component, signal } from '@angular/core';
import { ToolbarComponent, type MenuItem, type ToolbarItem } from 'ui';

@Component({
  selector: 'app-toolbar-split-actions-demo',
  standalone: true,
  imports: [ToolbarComponent],
  template: `
    <div
      style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%;max-width:52rem"
    >
      <div
        style="flex:0 0 28rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <ui-toolbar [items]="items" (itemClick)="lastAction.set($event.label || $event.id)" />
      </div>

      <div
        style="flex:1 1 16rem;padding:0.875rem 1rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background2-rest)"
      >
        <p
          style="margin:0 0 0.5rem;font-size:0.75rem;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;color:var(--color-neutral-foreground2-rest)"
        >
          Last action
        </p>
        <div style="font-size:0.875rem;line-height:1.5;color:var(--color-neutral-foreground-rest)">
          {{ lastAction() || 'No action yet.' }}
        </div>
      </div>
    </div>
  `,
})
export class ToolbarSplitActionsDemoComponent {
  protected readonly lastAction = signal('');

  protected readonly items: ToolbarItem[] = [
    {
      id: 'save',
      type: 'split',
      label: 'Save',
      icon: 'save',
      variant: 'primary',
      menuItems: this.createMenuItems('Save'),
    },
    {
      id: 'publish',
      type: 'split',
      label: 'Publish',
      icon: 'rocket',
      appearance: 'outline',
      menuItems: this.createMenuItems('Publish'),
    },
    { id: 'preview', label: 'Preview', icon: 'eye', tooltip: 'Preview' },
  ];

  private createMenuItems(label: string): MenuItem[] {
    return [
      { id: `${label}-as`, label: `${label} as copy` },
      { id: `${label}-all`, label: `${label} all` },
      { id: `${label}-draft`, label: `${label} draft only` },
    ];
  }
}
```

## Overflow in constrained space
```ts
import { Component } from '@angular/core';
import { ToolbarComponent, type ToolbarItem } from 'ui';

@Component({
  selector: 'app-toolbar-overflow-demo',
  standalone: true,
  imports: [ToolbarComponent],
  template: `
    <div
      style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%;max-width:52rem"
    >
      <div
        style="flex:0 0 20rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest);resize:horizontal;overflow:auto;min-width:16rem;max-width:32rem"
      >
        <p
          style="margin:0 0 0.75rem;font-size:0.875rem;font-weight:600;color:var(--color-neutral-foreground2-rest)"
        >
          Resizable overflow toolbar
        </p>
        <ui-toolbar [items]="items" [overflow]="true" />
      </div>

      <div
        style="flex:1 1 16rem;padding:0.875rem 1rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background2-rest)"
      >
        <div style="display:grid;gap:0.5rem;font-size:0.875rem;line-height:1.5">
          <div>
            Use overflow when the action count is variable or the toolbar lives in a constrained
            shell.
          </div>
          <div>Resize the card to test how the row wraps and compresses in smaller spaces.</div>
        </div>
      </div>
    </div>
  `,
})
export class ToolbarOverflowDemoComponent {
  protected readonly items: ToolbarItem[] = [
    { id: 'new', label: 'New', icon: 'document_add', tooltip: 'New' },
    { id: 'open', label: 'Open', icon: 'folder_open', tooltip: 'Open' },
    { id: 'save', label: 'Save', icon: 'save', tooltip: 'Save' },
    { id: 'print', label: 'Print', icon: 'print', tooltip: 'Print' },
    { id: 'share', label: 'Share', icon: 'share', tooltip: 'Share' },
    { id: 'comment', label: 'Comment', icon: 'comment', tooltip: 'Comment' },
    { id: 'history', label: 'History', icon: 'history', tooltip: 'History' },
  ];
}
```

## Composition with other controls
```ts
import { Component } from '@angular/core';
import {
  DividerComponent,
  DropdownComponent,
  TextComponent,
  ToolbarComponent,
  type DropdownItem,
  type ToolbarGroup,
} from 'ui';

@Component({
  selector: 'app-toolbar-editor-header-demo',
  standalone: true,
  imports: [DividerComponent, DropdownComponent, TextComponent, ToolbarComponent],
  template: `
    <div
      style="display:flex;flex-wrap:wrap;align-items:center;gap:0.75rem;width:100%;max-width:58rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <ui-toolbar [groups]="groups" />
      <ui-divider orientation="vertical" />
      <ui-dropdown [items]="fontSizeItems" placeholder="Size" style="width:7rem" />
      <ui-dropdown [items]="fontFamilyItems" placeholder="Font" style="width:10rem" />
      <ui-text placeholder="Find in document..." style="width:12rem" />
    </div>
  `,
})
export class ToolbarEditorHeaderDemoComponent {
  protected readonly groups: ToolbarGroup[] = [
    {
      id: 'file',
      items: [
        { id: 'save', icon: 'save', tooltip: 'Save' },
        { id: 'share', icon: 'share', tooltip: 'Share' },
      ],
    },
    {
      id: 'format',
      items: [
        { id: 'bold', icon: 'text_bold', tooltip: 'Bold', type: 'toggle', selected: true },
        { id: 'italic', icon: 'text_italic', tooltip: 'Italic', type: 'toggle' },
        { id: 'underline', icon: 'text_underline', tooltip: 'Underline', type: 'toggle' },
      ],
    },
  ];

  protected readonly fontSizeItems: DropdownItem[] = [
    { value: '12', label: '12' },
    { value: '14', label: '14' },
    { value: '16', label: '16' },
    { value: '20', label: '20' },
  ];

  protected readonly fontFamilyItems: DropdownItem[] = [
    { value: 'segoe', label: 'Segoe UI' },
    { value: 'calibri', label: 'Calibri' },
    { value: 'georgia', label: 'Georgia' },
  ];
}
```

## Buttons, toggles, splits, dividers, and custom content
```ts
import { Component } from '@angular/core';
import { BadgeComponent, ToolbarComponent, type ToolbarItem } from 'ui';

@Component({
  selector: 'app-toolbar-all-types-demo',
  standalone: true,
  imports: [BadgeComponent, ToolbarComponent],
  template: `
    <div
      style="width:100%;max-width:46rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <ui-toolbar [items]="items">
        <ui-badge
          text="Draft"
          size="small"
          appearance="outline"
          variant="secondary"
          shape="rounded"
        />
      </ui-toolbar>
    </div>
  `,
})
export class ToolbarAllTypesDemoComponent {
  protected readonly items: ToolbarItem[] = [
    { id: 'new', label: 'New', icon: 'document_add' },
    { id: 'divider-a', type: 'divider' },
    { id: 'bold', type: 'toggle', icon: 'text_bold', selected: true, tooltip: 'Bold' },
    {
      id: 'save',
      type: 'split',
      label: 'Save',
      icon: 'save',
      menuItems: [
        { id: 'save-as', label: 'Save as copy' },
        { id: 'save-all', label: 'Save all' },
      ],
    },
    { id: 'divider-b', type: 'divider' },
    { id: 'custom-slot', type: 'custom' },
  ];
}
```

## Accessibility

### Toolbar semantics
`ui-toolbar` groups related actions into one command surface. Individual controls inside the toolbar keep their own semantics, such as button, toggle button, menu button, or custom projected content.

### Keyboard behavior
Keyboard behavior primarily comes from the controls placed inside the toolbar.

| Key | Action |
| --- | --- |
| Tab / Shift+Tab | Move focus into, through, and out of the toolbar according to document order. |
| Enter / Space | Activate the focused button, toggle, or split action. |
| Arrow keys | Follow the behavior of the focused inner control or menu when applicable. |

### Labels and tooltips
Icon-only actions should still expose a clear accessible name through `ariaLabel`, `label`, or tooltip-derived labeling. When you project custom content, make sure that content remains keyboard reachable and semantically clear.
