---
title: Menubar
description: Horizontal menu bar with dropdowns
visibility: guest
draft: false
---

# Menubar

The `<x-wirekit::menubar>` component creates a horizontal menu bar with dropdown menus, following the [WAI-ARIA Menubar pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menubar/). It is designed for desktop application-style interfaces with menus like File, Edit, View.

## Usage

:::preview{title="Application Menubar"}
<x-wirekit::menubar>
    <x-wirekit::menubar.menu label="File">
        <x-wirekit::menubar.item shortcut="Ctrl+N">New File</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+O">Open</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+S">Save</x-wirekit::menubar.item>
        <x-wirekit::menubar.separator />
        <x-wirekit::menubar.item :danger="true">Exit</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>
    <x-wirekit::menubar.menu label="Edit">
        <x-wirekit::menubar.item shortcut="Ctrl+Z">Undo</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+Y">Redo</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>
    <x-wirekit::menubar.menu label="View">
        <x-wirekit::menubar.item>Zoom In</x-wirekit::menubar.item>
        <x-wirekit::menubar.item>Zoom Out</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>
</x-wirekit::menubar>
:::

## Basic Setup

```blade
<x-wirekit::menubar>
    <x-wirekit::menubar.menu label="File">
        <x-wirekit::menubar.item shortcut="Ctrl+N">New File</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+O">Open</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+S">Save</x-wirekit::menubar.item>
        <x-wirekit::menubar.separator />
        <x-wirekit::menubar.item :danger="true">Exit</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>

    <x-wirekit::menubar.menu label="Edit">
        <x-wirekit::menubar.item shortcut="Ctrl+Z">Undo</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+Y">Redo</x-wirekit::menubar.item>
        <x-wirekit::menubar.separator />
        <x-wirekit::menubar.item shortcut="Ctrl+X">Cut</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+C">Copy</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+V">Paste</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>

    <x-wirekit::menubar.menu label="View">
        <x-wirekit::menubar.item>Zoom In</x-wirekit::menubar.item>
        <x-wirekit::menubar.item>Zoom Out</x-wirekit::menubar.item>
        <x-wirekit::menubar.separator />
        <x-wirekit::menubar.item>Full Screen</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>
</x-wirekit::menubar>
```

## Items with Links

Items can act as navigation links. The example below ships three top-level menus to mirror the canonical macOS / shadcn menubar pattern — a single-trigger menubar reads as a "button-in-a-button" because the parent border has no other menus to balance against.

:::preview{title="Menubar with Link Items"}
<x-wirekit::menubar>
    <x-wirekit::menubar.menu label="File">
        <x-wirekit::menubar.item href="#">Dashboard</x-wirekit::menubar.item>
        <x-wirekit::menubar.item href="#">Settings</x-wirekit::menubar.item>
        <x-wirekit::menubar.item href="#">Profile</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>
    <x-wirekit::menubar.menu label="Edit">
        <x-wirekit::menubar.item href="#">Cut</x-wirekit::menubar.item>
        <x-wirekit::menubar.item href="#">Copy</x-wirekit::menubar.item>
        <x-wirekit::menubar.item href="#">Paste</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>
    <x-wirekit::menubar.menu label="Help">
        <x-wirekit::menubar.item href="#">Documentation</x-wirekit::menubar.item>
        <x-wirekit::menubar.item href="#">Keyboard Shortcuts</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>
</x-wirekit::menubar>
:::

## Danger Items

Use the `danger` prop for destructive actions:

:::preview{title="Danger and Disabled Items"}
<x-wirekit::menubar>
    <x-wirekit::menubar.menu label="Project">
        <x-wirekit::menubar.item>Rename</x-wirekit::menubar.item>
        <x-wirekit::menubar.item>Duplicate</x-wirekit::menubar.item>
        <x-wirekit::menubar.separator />
        <x-wirekit::menubar.item :disabled="true">Paste (clipboard empty)</x-wirekit::menubar.item>
        <x-wirekit::menubar.separator />
        <x-wirekit::menubar.item :danger="true">Delete Project</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>
</x-wirekit::menubar>
:::

Disabled items are visually muted, not focusable via keyboard navigation, and have `aria-disabled="true"`.

## Keyboard Shortcuts Display

The `shortcut` prop renders a secondary label on the right side of the item. It is display-only and does not register actual keyboard handlers:

:::preview{title="Menubar with Keyboard Shortcuts"}
<x-wirekit::menubar>
    <x-wirekit::menubar.menu label="File">
        <x-wirekit::menubar.item shortcut="Ctrl+N">New File</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+S">Save</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+Shift+S">Save As</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>
    <x-wirekit::menubar.menu label="Edit">
        <x-wirekit::menubar.item shortcut="Ctrl+Z">Undo</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+Y">Redo</x-wirekit::menubar.item>
        <x-wirekit::menubar.separator />
        <x-wirekit::menubar.item shortcut="Ctrl+X">Cut</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+C">Copy</x-wirekit::menubar.item>
        <x-wirekit::menubar.item shortcut="Ctrl+V">Paste</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>
</x-wirekit::menubar>
:::

To register real keyboard shortcuts, use Alpine or Livewire listeners separately.

## Submenus

Nest a `<x-wirekit::menubar.submenu>` inside a menu to add a flyout sub-menu (e.g. "Export As → PDF / PNG"). The parent item opens a child panel beside it (on hover, click, or `ArrowRight`); the child holds ordinary `<x-wirekit::menubar.item>`s.

:::preview{title="Menubar with a submenu"}
<x-wirekit::menubar>
    <x-wirekit::menubar.menu label="File">
        <x-wirekit::menubar.item shortcut="Ctrl+N">New File</x-wirekit::menubar.item>
        <x-wirekit::menubar.submenu label="Export As">
            <x-wirekit::menubar.item>PDF</x-wirekit::menubar.item>
            <x-wirekit::menubar.item>PNG</x-wirekit::menubar.item>
            <x-wirekit::menubar.item>SVG</x-wirekit::menubar.item>
        </x-wirekit::menubar.submenu>
        <x-wirekit::menubar.separator />
        <x-wirekit::menubar.item :danger="true">Exit</x-wirekit::menubar.item>
    </x-wirekit::menubar.menu>
</x-wirekit::menubar>
:::

The parent carries `aria-haspopup="menu"` + `aria-expanded`; the child panel is its own `role="menu"`. `ArrowRight` on a submenu parent opens the submenu (rather than moving to the next top-level menu); `ArrowLeft` / `Escape` close it. Submenus nest arbitrarily deep.

## Behavior

- **Hover-to-switch:** when one menu is open, hovering another menu trigger opens it immediately (no click needed)
- **[Floating UI](https://floating-ui.com/)** (bundled ~3.5 KB) positions menus below their triggers with flip and shift
- **Click outside** closes any open menu
- **Livewire SPA** navigation (`wire:navigate`) automatically closes open menus
- **Transitions** use scale + opacity for smooth open/close animation

## Props

### `<x-wirekit::menubar>`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `scope` | `string\|null` | `null` | Scoped personalization key |

### `<x-wirekit::menubar.menu>`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | **required** | Visible menu trigger text (e.g. "File", "Edit") |
| `scope` | `string\|null` | `null` | Scoped personalization key |

### `<x-wirekit::menubar.item>`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `href` | `string\|null` | `null` | URL (renders `<a>` instead of `<button>`) |
| `danger` | `bool` | `false` | Destructive/danger styling |
| `disabled` | `bool` | `false` | Disabled state |
| `shortcut` | `string\|null` | `null` | Keyboard shortcut display text (visual only) |
| `scope` | `string\|null` | `null` | Scoped personalization key |

### `<x-wirekit::menubar.submenu>`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string\|null` | `null` | Parent item text (or pass a `<x-slot:label>` for rich content) |
| `icon` | `string\|null` | `null` | Optional leading icon (WireKit icon alias) |
| `placement` | `string` | `'right-start'` | [Floating UI placement](https://floating-ui.com/docs/computePosition#placement) of the child panel |
| `offset` | `int` | `0` | Distance in px between the parent item and the child panel |
| `disabled` | `bool` | `false` | Disabled state |
| `scope` | `string\|null` | `null` | Scoped personalization key |

## Sub-Components

| Component | Purpose |
| --- | --- |
| `menubar.menu` | A single top-level menu trigger with its dropdown |
| `menubar.item` | A menu entry inside a menu (link or action) |
| `menubar.submenu` | A nested flyout sub-menu opened from a menu item |
| `menubar.separator` | Visual divider between item groups |

## Accessibility

- Menubar wrapper: `role="menubar"`, horizontal orientation
- Menu triggers: `role="menuitem"`, `aria-haspopup="menu"`, `aria-expanded` (dynamic)
- Menu panels: `role="menu"`, `aria-label` from the `label` prop
- Menu items: `role="menuitem"`, `tabindex="-1"`
- Disabled items: `aria-disabled="true"`, skipped by keyboard navigation
- **Roving tabindex:** only the active menu trigger in the bar has `tabindex="0"`; others have `tabindex="-1"`
- **Focus management:** opening a menu focuses the first item; closing returns focus to the trigger
- Icons: `aria-hidden="true"` (decorative)

## Keyboard Interaction

The menubar implements the full [WAI-ARIA Menubar keyboard pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menubar/):

| Key | Context | Action |
| --- | --- | --- |
| Tab | Menubar | Move focus into / out of the menubar |
| Arrow Left / Right | Menubar | Move focus between top-level menu triggers |
| Enter / Space | Menu trigger | Open the menu, focus first item |
| Arrow Down | Menu trigger | Open the menu, focus first item |
| Arrow Up | Menu trigger | Open the menu, focus last item |
| Arrow Down / Up | Open menu | Move to next / previous item |
| Home / End | Open menu | Jump to first / last item |
| Enter / Space | Menu item | Activate the focused item |
| Escape | Open menu | Close menu, return focus to menu trigger |
| Arrow Left / Right | Open menu | Close current, open adjacent menu |
| Arrow Right | Submenu parent | Open the submenu and focus its first item |
| Arrow Left / Escape | Inside a submenu | Close the submenu, return focus to the parent item |

## Pitfalls

- **Don't use menubar for application-wide navigation.** WAI-ARIA Authoring Practices reserve menubars for app-internal commands (Edit > Copy). For site navigation reach for `<x-wirekit::navigation-menu>`.
- **Don't combine menubar with a sidebar nav.** Two competing keyboard wayfinding patterns exhaust focus management — pick one.

## Design Tokens

| Element | Token |
| --- | --- |
| Bar background | `--color-wk-bg-elevated` |
| Bar border | `--color-wk-border` / `--border-wk-width` |
| Trigger text | `--color-wk-text` |
| Trigger hover bg | `--color-wk-bg-subtle` |
| Trigger active bg | `--color-wk-bg-subtle` |
| Trigger radius | `--radius-wk-md` |
| Menu background | `--color-wk-bg-elevated` |
| Menu border | `--color-wk-border` |
| Menu radius | `--radius-wk-lg` |
| Menu shadow | `--shadow-wk-lg` |
| Item text | `--color-wk-text` |
| Item hover bg | `--color-wk-bg-subtle` |
| Item radius | `--radius-wk-md` |
| Danger text | `--color-wk-danger-text` |
| Shortcut text | `--color-wk-text-muted` |
| Separator color | `--color-wk-border-subtle` |
| Font family | `--font-wk-sans` |
| Font size | `--text-wk-md` |
| Disabled opacity | `--opacity-wk-disabled` |
| Transition | `--transition-wk-duration` |

## Personalization

Override defaults in `config/wirekit.php`:

```php
'components' => [
    'menubar' => [],
],
```

### Scoped Personalization

```blade
<x-wirekit::menubar scope="editor-toolbar">
    ...
</x-wirekit::menubar>
```

```php
'personalizations' => [
    'menubar' => [
        'editor-toolbar' => [
            'base' => 'border-b-2',
        ],
    ],
],
```

## Further Reading

- [WAI-ARIA Menubar Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menubar/) -- the authoring pattern this component implements
- [WAI-ARIA Menu Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menu/) -- individual dropdown menus
- [MDN: `role="menubar"`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menubar_role)
- [MDN: `role="menu"`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menu_role)
- [MDN: `role="menuitem"`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menuitem_role)
- [Floating UI](https://floating-ui.com/) -- positioning engine (bundled, ~3.5 KB)
