# Speed Dial

Speed Dial works best for high-value secondary actions that should stay nearby but hidden until needed. It supports linear, circle, semi-circle, and quarter-circle layouts, optional masking, idle close behavior, tooltip labels, and coordination so only one dial stays open at a time.

## Import
```ts
import { SpeedDialComponent, type MenuItem } from 'ui';
```

## Linear directions
```ts
import { Component, signal } from '@angular/core';
import { MenuItem, SpeedDialComponent } from 'ui';

@Component({
  selector: 'app-speed-dial-linear-demo',
  standalone: true,
  imports: [SpeedDialComponent],
  template: `
    <section
      style="display:grid;gap:1rem;max-width:56rem;padding:1.25rem;border:1px solid color-mix(in srgb,var(--color-neutral-stroke-rest) 70%,transparent);border-radius:1rem;background:color-mix(in srgb,var(--color-neutral-background-rest) 92%,white);"
    >
      <div style="display:grid;gap:0.25rem;">
        <h3 style="margin:0;font-size:1rem;">Linear directions</h3>
        <p style="margin:0;font-size:0.875rem;color:var(--color-neutral-foreground2-rest);">
          Linear is the safest layout for edge-triggered quick actions because the expansion path
          stays predictable.
        </p>
      </div>

      <div
        style="display:grid;grid-template-columns:minmax(88px,1fr) auto minmax(88px,1fr);grid-template-rows:minmax(112px,auto) minmax(160px,1fr) minmax(112px,auto);grid-template-areas:'. top .' 'left hub right' '. bottom .';min-height:420px;padding:12px 28px 20px;align-items:center;justify-items:center;border:1px solid var(--color-neutral-stroke1-rest);border-radius:12px;background:var(--color-neutral-background-rest);box-shadow:0 1px 3px rgb(0 0 0 / 10%), inset 0 0 0 1px var(--color-neutral-stroke2-rest);"
      >
        <div
          style="grid-area:hub;font-size:11px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:var(--color-neutral-foreground3-rest);user-select:none;"
        >
          Linear
        </div>
        <div
          style="grid-area:bottom;display:flex;flex-direction:column;align-items:center;gap:8px;align-self:end;"
        >
          <span style="font-size:11px;font-weight:600;color:var(--color-neutral-foreground3-rest);"
            >Up</span
          >
          <ui-speed-dial
            dialType="linear"
            direction="up"
            [itemSizePx]="40"
            [gap]="6"
            [items]="items()"
            [triggerButtonProps]="{ variant: 'primary', appearance: 'filled', shape: 'circular' }"
            ariaLabel="Linear up actions"
          />
        </div>
        <div
          style="grid-area:top;display:flex;flex-direction:column;align-items:center;gap:8px;align-self:start;"
        >
          <span style="font-size:11px;font-weight:600;color:var(--color-neutral-foreground3-rest);"
            >Down</span
          >
          <ui-speed-dial
            dialType="linear"
            direction="down"
            [itemSizePx]="40"
            [gap]="6"
            [items]="items()"
            [triggerButtonProps]="{ variant: 'primary', appearance: 'filled', shape: 'circular' }"
            ariaLabel="Linear down actions"
          />
        </div>
        <div
          style="grid-area:left;display:flex;flex-direction:column;align-items:center;gap:8px;justify-self:start;"
        >
          <span style="font-size:11px;font-weight:600;color:var(--color-neutral-foreground3-rest);"
            >Right</span
          >
          <ui-speed-dial
            dialType="linear"
            direction="right"
            [itemSizePx]="40"
            [gap]="6"
            [items]="items()"
            [triggerButtonProps]="{ variant: 'primary', appearance: 'filled', shape: 'circular' }"
            ariaLabel="Linear right actions"
          />
        </div>
        <div
          style="grid-area:right;display:flex;flex-direction:column;align-items:center;gap:8px;justify-self:end;"
        >
          <span style="font-size:11px;font-weight:600;color:var(--color-neutral-foreground3-rest);"
            >Left</span
          >
          <ui-speed-dial
            dialType="linear"
            direction="left"
            [itemSizePx]="40"
            [gap]="6"
            [items]="items()"
            [triggerButtonProps]="{ variant: 'primary', appearance: 'filled', shape: 'circular' }"
            ariaLabel="Linear left actions"
          />
        </div>
      </div>
    </section>
  `,
})
export class SpeedDialLinearDemoComponent {
  protected readonly items = signal<MenuItem[]>([
    { id: 'edit', label: '', icon: 'edit' },
    { id: 'refresh', label: '', icon: 'arrow_sync' },
    { id: 'delete', label: '', icon: 'delete' },
    { id: 'open', label: '', icon: 'open' },
  ]);
}
```

## Circle layout
```ts
import { Component, signal } from '@angular/core';
import { MenuItem, SpeedDialComponent } from 'ui';

@Component({
  selector: 'app-speed-dial-circle-demo',
  standalone: true,
  imports: [SpeedDialComponent],
  template: `
    <section
      style="display:grid;gap:1rem;max-width:42rem;padding:1.25rem;border:1px solid color-mix(in srgb,var(--color-neutral-stroke-rest) 70%,transparent);border-radius:1rem;background:color-mix(in srgb,var(--color-neutral-background-rest) 92%,white);"
    >
      <div style="display:grid;gap:0.25rem;">
        <h3 style="margin:0;font-size:1rem;">Circle layout</h3>
        <p style="margin:0;font-size:0.875rem;color:var(--color-neutral-foreground2-rest);">
          Full radial layout works best when the trigger owns enough surrounding space and the dial
          is itself a focal interaction.
        </p>
      </div>
      <div
        style="display:flex;align-items:center;justify-content:center;min-height:380px;padding:48px 32px;border:1px solid var(--color-neutral-stroke1-rest);border-radius:12px;background:var(--color-neutral-background-rest);box-shadow:0 1px 3px rgb(0 0 0 / 10%), inset 0 0 0 1px var(--color-neutral-stroke2-rest);"
      >
        <ui-speed-dial
          dialType="circle"
          [radius]="72"
          [itemSizePx]="40"
          [gap]="6"
          [items]="items()"
          [triggerButtonProps]="{ variant: 'primary', appearance: 'filled', shape: 'circular' }"
          ariaLabel="Circle speed dial"
        />
      </div>
    </section>
  `,
})
export class SpeedDialCircleDemoComponent {
  protected readonly items = signal<MenuItem[]>([
    { id: 'comment', label: '', icon: 'chat' },
    { id: 'share', label: '', icon: 'share' },
    { id: 'archive', label: '', icon: 'archive' },
    { id: 'pin', label: '', icon: 'pin' },
    { id: 'copy', label: '', icon: 'copy' },
    { id: 'star', label: '', icon: 'star' },
  ]);
}
```

## Semi and quarter arcs
```ts
import { Component, signal } from '@angular/core';
import { MenuItem, SpeedDialComponent } from 'ui';

@Component({
  selector: 'app-speed-dial-arc-demo',
  standalone: true,
  imports: [SpeedDialComponent],
  template: `
    <section
      style="display:grid;gap:1rem;max-width:56rem;padding:1.25rem;border:1px solid color-mix(in srgb,var(--color-neutral-stroke-rest) 70%,transparent);border-radius:1rem;background:color-mix(in srgb,var(--color-neutral-background-rest) 92%,white);"
    >
      <div style="display:grid;gap:0.25rem;">
        <h3 style="margin:0;font-size:1rem;">Semi and quarter arcs</h3>
        <p style="margin:0;font-size:0.875rem;color:var(--color-neutral-foreground2-rest);">
          Arc layouts are useful when the trigger sits on an edge or in a corner and the actions
          should expand inward.
        </p>
      </div>
      <div style="display:grid;gap:1rem;">
        <div
          style="display:grid;gap:0.75rem;padding:1rem;border:1px solid var(--color-neutral-stroke1-rest);border-radius:12px;background:var(--color-neutral-background-rest);"
        >
          <strong style="font-size:0.875rem;">Semi-circle</strong>
          <div
            style="display:grid;grid-template-columns:minmax(112px,1fr) auto minmax(112px,1fr);grid-template-rows:minmax(112px,auto) minmax(176px,1fr) minmax(112px,auto);grid-template-areas:'. top .' 'left hub right' '. bottom .';min-height:360px;padding:20px 28px 24px;align-items:center;justify-items:center;border:1px dashed color-mix(in srgb,var(--color-neutral-stroke-rest) 65%,transparent);border-radius:12px;background:color-mix(in srgb,var(--color-neutral-background2-rest) 70%,white);"
          >
            <div
              style="grid-area:hub;font-size:11px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:var(--color-neutral-foreground3-rest);user-select:none;"
            >
              Semi
            </div>
            <div
              style="grid-area:bottom;display:flex;flex-direction:column;align-items:center;gap:8px;align-self:end;"
            >
              <span
                style="font-size:11px;font-weight:600;color:var(--color-neutral-foreground3-rest);"
                >Up</span
              >
              <ui-speed-dial
                dialType="semi-circle"
                direction="up"
                [radius]="60"
                [itemSizePx]="40"
                [gap]="6"
                [items]="items()"
                [triggerButtonProps]="{
                  variant: 'primary',
                  appearance: 'filled',
                  shape: 'circular',
                }"
                ariaLabel="Semi circle up actions"
              />
            </div>
            <div
              style="grid-area:right;display:flex;flex-direction:column;align-items:center;gap:8px;justify-self:end;"
            >
              <span
                style="font-size:11px;font-weight:600;color:var(--color-neutral-foreground3-rest);"
                >Left</span
              >
              <ui-speed-dial
                dialType="semi-circle"
                direction="left"
                [radius]="60"
                [itemSizePx]="40"
                [gap]="6"
                [items]="items()"
                [triggerButtonProps]="{
                  variant: 'primary',
                  appearance: 'filled',
                  shape: 'circular',
                }"
                ariaLabel="Semi circle left actions"
              />
            </div>
          </div>
        </div>

        <div
          style="display:grid;gap:0.75rem;padding:1rem;border:1px solid var(--color-neutral-stroke1-rest);border-radius:12px;background:var(--color-neutral-background-rest);"
        >
          <strong style="font-size:0.875rem;">Quarter-circle</strong>
          <div
            style="position:relative;min-height:360px;padding:32px;border:1px dashed color-mix(in srgb,var(--color-neutral-stroke-rest) 65%,transparent);border-radius:12px;background:color-mix(in srgb,var(--color-neutral-background2-rest) 70%,white);"
          >
            <div
              style="position:absolute;top:32px;left:32px;display:flex;flex-direction:column;align-items:flex-start;gap:8px;"
            >
              <span
                style="font-size:11px;font-weight:600;color:var(--color-neutral-foreground3-rest);"
                >Down right</span
              >
              <ui-speed-dial
                dialType="quarter-circle"
                direction="down-right"
                [radius]="72"
                [itemSizePx]="40"
                [gap]="6"
                [items]="items()"
                [triggerButtonProps]="{
                  variant: 'primary',
                  appearance: 'filled',
                  shape: 'circular',
                }"
                ariaLabel="Quarter circle down right actions"
              />
            </div>
            <div
              style="position:absolute;bottom:32px;right:32px;display:flex;flex-direction:column;align-items:flex-end;gap:8px;"
            >
              <span
                style="font-size:11px;font-weight:600;color:var(--color-neutral-foreground3-rest);"
                >Up left</span
              >
              <ui-speed-dial
                dialType="quarter-circle"
                direction="up-left"
                [radius]="72"
                [itemSizePx]="40"
                [gap]="6"
                [items]="items()"
                [triggerButtonProps]="{
                  variant: 'primary',
                  appearance: 'filled',
                  shape: 'circular',
                }"
                ariaLabel="Quarter circle up left actions"
              />
            </div>
          </div>
        </div>
      </div>
    </section>
  `,
})
export class SpeedDialArcDemoComponent {
  protected readonly items = signal<MenuItem[]>([
    { id: 'add', label: '', icon: 'add' },
    { id: 'duplicate', label: '', icon: 'copy' },
    { id: 'move', label: '', icon: 'arrow_move' },
    { id: 'remove', label: '', icon: 'delete' },
  ]);
}
```

## Mask, idle close, and tooltips
```ts
import { Component, signal } from '@angular/core';
import { MenuItem, SpeedDialComponent } from 'ui';

@Component({
  selector: 'app-speed-dial-behavior-demo',
  standalone: true,
  imports: [SpeedDialComponent],
  template: `
    <section
      style="display:grid;gap:1rem;max-width:56rem;padding:1.25rem;border:1px solid color-mix(in srgb,var(--color-neutral-stroke-rest) 70%,transparent);border-radius:1rem;background:color-mix(in srgb,var(--color-neutral-background-rest) 92%,white);"
    >
      <div style="display:grid;gap:0.25rem;">
        <h3 style="margin:0;font-size:1rem;">Mask, idle close, and tooltips</h3>
        <p style="margin:0;font-size:0.875rem;color:var(--color-neutral-foreground2-rest);">
          These options affect how disruptive or discoverable the dial feels in a busy screen.
        </p>
      </div>
      <div
        style="display:grid;grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));gap:28px 20px;min-height:260px;padding:28px 24px 32px;border:1px solid var(--color-neutral-stroke1-rest);border-radius:12px;background:var(--color-neutral-background-rest);align-items:end;justify-items:center;"
      >
        <div
          style="min-height:200px;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:8px;"
        >
          <span style="font-size:11px;font-weight:600;color:var(--color-neutral-foreground3-rest);"
            >Idle 5s</span
          >
          <ui-speed-dial
            dialType="linear"
            direction="up"
            [autoCloseIdleMs]="5000"
            [itemSizePx]="40"
            [gap]="6"
            [items]="items()"
            [triggerButtonProps]="{ variant: 'primary', appearance: 'filled', shape: 'circular' }"
            ariaLabel="Idle close speed dial"
            (hide)="log('idle: ' + $event.type)"
          />
        </div>
        <div
          style="min-height:200px;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:8px;"
        >
          <span style="font-size:11px;font-weight:600;color:var(--color-neutral-foreground3-rest);"
            >Mask</span
          >
          <ui-speed-dial
            dialType="linear"
            direction="up"
            [mask]="true"
            [itemSizePx]="40"
            [gap]="6"
            [items]="items()"
            [triggerButtonProps]="{ variant: 'primary', appearance: 'filled', shape: 'circular' }"
            ariaLabel="Masked speed dial"
          />
        </div>
        <div
          style="min-height:200px;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:8px;"
        >
          <span style="font-size:11px;font-weight:600;color:var(--color-neutral-foreground3-rest);"
            >Tooltips</span
          >
          <ui-speed-dial
            dialType="linear"
            direction="up"
            [showTooltips]="true"
            [tooltipOptions]="{ tooltipPosition: 'left' }"
            [itemSizePx]="40"
            [gap]="6"
            [items]="tooltipItems()"
            [triggerButtonProps]="{ variant: 'secondary', appearance: 'filled', shape: 'circular' }"
            ariaLabel="Tooltip speed dial"
          />
        </div>
      </div>
      <div
        style="display:flex;flex-wrap:wrap;gap:12px;padding:12px 14px;border:1px dashed var(--color-neutral-stroke-rest);border-radius:12px;background:var(--color-neutral-background2-rest);"
      >
        <div style="font-weight:600;">Event log</div>
        <div>{{ eventLog().length > 0 ? eventLog()[0] : 'No events yet.' }}</div>
      </div>
    </section>
  `,
})
export class SpeedDialBehaviorDemoComponent {
  protected readonly eventLog = signal<string[]>([]);
  protected readonly items = signal<MenuItem[]>([
    { id: 'edit', label: '', icon: 'edit', action: () => this.log('action: edit') },
    { id: 'refresh', label: '', icon: 'arrow_sync', action: () => this.log('action: refresh') },
    { id: 'delete', label: '', icon: 'delete', action: () => this.log('action: delete') },
  ]);
  protected readonly tooltipItems = signal<MenuItem[]>([
    { id: 'Add', label: '', icon: 'add', action: () => this.log('action: add') },
    { id: 'Update', label: '', icon: 'arrow_sync', action: () => this.log('action: update') },
    { id: 'Remove', label: '', icon: 'delete', action: () => this.log('action: remove') },
  ]);

  protected log(message: string): void {
    this.eventLog.update(entries => [message, ...entries].slice(0, 12));
  }
}
```

## Coordination between dials
```ts
import { Component, signal } from '@angular/core';
import { MenuItem, SpeedDialComponent } from 'ui';

@Component({
  selector: 'app-speed-dial-coordination-demo',
  standalone: true,
  imports: [SpeedDialComponent],
  template: `
    <section
      style="display:grid;gap:1rem;max-width:48rem;padding:1.25rem;border:1px solid color-mix(in srgb,var(--color-neutral-stroke-rest) 70%,transparent);border-radius:1rem;background:color-mix(in srgb,var(--color-neutral-background-rest) 92%,white);"
    >
      <div style="display:grid;gap:0.25rem;">
        <h3 style="margin:0;font-size:1rem;">Coordination between dials</h3>
        <p style="margin:0;font-size:0.875rem;color:var(--color-neutral-foreground2-rest);">
          Multiple floating triggers should usually coordinate so only one menu stays open at a
          time.
        </p>
      </div>
      <div
        style="display:grid;grid-template-columns:repeat(auto-fit,minmax(14rem,1fr));gap:1rem;min-height:280px;padding:1rem;border:1px solid var(--color-neutral-stroke1-rest);border-radius:12px;background:var(--color-neutral-background-rest);"
      >
        <article
          style="position:relative;min-height:220px;padding:1rem;border-radius:12px;background:var(--color-neutral-background2-rest);"
        >
          <div style="display:grid;gap:0.25rem;">
            <strong>Primary actions</strong>
            <span style="font-size:0.875rem;color:var(--color-neutral-foreground2-rest);"
              >Create, assign, and start work.</span
            >
          </div>
          <div style="position:absolute;right:16px;bottom:16px;">
            <ui-speed-dial
              dialType="linear"
              direction="up"
              [items]="primaryItems()"
              [itemSizePx]="40"
              [gap]="6"
              [triggerButtonProps]="{ variant: 'primary', appearance: 'filled', shape: 'circular' }"
              ariaLabel="Primary speed dial"
            />
          </div>
        </article>
        <article
          style="position:relative;min-height:220px;padding:1rem;border-radius:12px;background:var(--color-neutral-background2-rest);"
        >
          <div style="display:grid;gap:0.25rem;">
            <strong>Secondary actions</strong>
            <span style="font-size:0.875rem;color:var(--color-neutral-foreground2-rest);"
              >Share, archive, or open related records.</span
            >
          </div>
          <div style="position:absolute;right:16px;bottom:16px;">
            <ui-speed-dial
              dialType="linear"
              direction="up"
              [items]="secondaryItems()"
              [itemSizePx]="40"
              [gap]="6"
              [triggerButtonProps]="{
                variant: 'secondary',
                appearance: 'filled',
                shape: 'circular',
              }"
              ariaLabel="Secondary speed dial"
            />
          </div>
        </article>
      </div>
    </section>
  `,
})
export class SpeedDialCoordinationDemoComponent {
  protected readonly primaryItems = signal<MenuItem[]>([
    { id: 'create', label: '', icon: 'add' },
    { id: 'assign', label: '', icon: 'person_add' },
    { id: 'start', label: '', icon: 'play' },
  ]);
  protected readonly secondaryItems = signal<MenuItem[]>([
    { id: 'share', label: '', icon: 'share' },
    { id: 'archive', label: '', icon: 'archive' },
    { id: 'open', label: '', icon: 'open' },
  ]);
}
```

## Workspace composition
```ts
import { Component, signal } from '@angular/core';
import { ButtonComponent, MenuItem, SpeedDialComponent } from 'ui';

@Component({
  selector: 'app-speed-dial-workspace-demo',
  standalone: true,
  imports: [SpeedDialComponent, ButtonComponent],
  template: `
    <section
      style="display:grid;gap:1rem;max-width:56rem;padding:1.25rem;border:1px solid color-mix(in srgb,var(--color-neutral-stroke-rest) 70%,transparent);border-radius:1rem;background:color-mix(in srgb,var(--color-neutral-background-rest) 92%,white);"
    >
      <div style="display:grid;gap:0.25rem;">
        <h3 style="margin:0;font-size:1rem;">Workspace composition</h3>
        <p style="margin:0;font-size:0.875rem;color:var(--color-neutral-foreground2-rest);">
          A realistic speed dial usually complements an existing panel rather than floating alone on
          a blank canvas.
        </p>
      </div>
      <article
        style="position:relative;display:grid;gap:1rem;min-height:320px;padding:1.25rem 1.25rem 5rem;border-radius:14px;background:linear-gradient(180deg,color-mix(in srgb,var(--color-brand-background-2) 52%,white),var(--color-neutral-background-rest));border:1px solid color-mix(in srgb,var(--color-neutral-stroke-rest) 72%,transparent);"
      >
        <header
          style="display:flex;flex-wrap:wrap;justify-content:space-between;gap:1rem;align-items:flex-start;"
        >
          <div style="display:grid;gap:0.35rem;">
            <strong style="font-size:1rem;">Campaign workspace</strong>
            <span
              style="font-size:0.875rem;color:var(--color-neutral-foreground2-rest);max-width:34rem;"
            >
              Draft assets, schedule updates, and launch collaborative actions from one persistent
              floating trigger.
            </span>
          </div>
          <div style="display:flex;flex-wrap:wrap;gap:0.75rem;">
            <ui-button text="Preview" variant="secondary" />
            <ui-button text="Publish" />
          </div>
        </header>
        <div
          style="display:grid;grid-template-columns:repeat(auto-fit,minmax(14rem,1fr));gap:0.875rem;"
        >
          <div
            style="padding:1rem;border-radius:12px;background:rgb(255 255 255 / 65%);border:1px solid color-mix(in srgb,var(--color-neutral-stroke-rest) 55%,transparent);"
          >
            <strong style="display:block;margin-bottom:0.5rem;">Assets</strong>
            <span style="font-size:0.875rem;color:var(--color-neutral-foreground2-rest);"
              >12 visuals, 3 pending approvals</span
            >
          </div>
          <div
            style="padding:1rem;border-radius:12px;background:rgb(255 255 255 / 65%);border:1px solid color-mix(in srgb,var(--color-neutral-stroke-rest) 55%,transparent);"
          >
            <strong style="display:block;margin-bottom:0.5rem;">Audience</strong>
            <span style="font-size:0.875rem;color:var(--color-neutral-foreground2-rest);"
              >EMEA, trial cohort, active customers</span
            >
          </div>
          <div
            style="padding:1rem;border-radius:12px;background:rgb(255 255 255 / 65%);border:1px solid color-mix(in srgb,var(--color-neutral-stroke-rest) 55%,transparent);"
          >
            <strong style="display:block;margin-bottom:0.5rem;">Timing</strong>
            <span style="font-size:0.875rem;color:var(--color-neutral-foreground2-rest);"
              >Launch window: next Tuesday at 10:00</span
            >
          </div>
        </div>
        <div style="position:absolute;right:20px;bottom:20px;">
          <ui-speed-dial
            dialType="semi-circle"
            direction="up"
            [radius]="72"
            [itemSizePx]="42"
            [gap]="8"
            [showTooltips]="true"
            [tooltipOptions]="{ tooltipPosition: 'left' }"
            [items]="items()"
            [triggerButtonProps]="{ variant: 'primary', appearance: 'filled', shape: 'circular' }"
            ariaLabel="Workspace speed dial"
          />
        </div>
      </article>
    </section>
  `,
})
export class SpeedDialWorkspaceDemoComponent {
  protected readonly items = signal<MenuItem[]>([
    { id: 'New draft', label: '', icon: 'edit' },
    { id: 'Assign review', label: '', icon: 'person_add' },
    { id: 'Schedule send', label: '', icon: 'calendar_clock' },
    { id: 'Duplicate', label: '', icon: 'copy' },
  ]);
}
```

## Accessibility

### Trigger and menu semantics
The trigger exposes menu semantics and controls a menu-like action list.

| Element | Accessibility behavior |
| --- | --- |
| trigger button | exposes `aria-haspopup`, `aria-expanded`, and `aria-controls` |
| action list | uses `role="menu"` |
| action buttons | use `role="menuitem"` with an accessible label |

### Keyboard and dismissal
The trigger itself follows normal button keyboard behavior. Once open, users should still be able to move through the revealed actions with normal focus navigation, and `Escape` dismisses the dial.

| Key | Action |
| --- | --- |
| `Enter` / `Space` on trigger | opens or closes the dial |
| `Tab` | moves between the trigger and visible actions |
| `Escape` | closes the open dial |
| click outside | closes the dial when `hideOnClickOutside` is enabled |

### Usage guidance
Only put a small set of meaningful actions in a speed dial. If the actions need long labels, dense grouping, or deep hierarchy, a menu, toolbar, or command palette is usually a better fit.
