Skip to main content
WireKit
Copy for LLM

Menubar

The <x-wirekit::menubar> component creates a horizontal menu bar with dropdown menus, following the WAI-ARIA Menubar pattern. It is designed for desktop application-style interfaces with menus like File, Edit, View.

Usage

Application Menubar

Basic Setup

<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 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.

Menubar with Link Items

Danger Items

Use the danger prop for destructive actions:

Danger and Disabled Items

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:

Menubar with Keyboard Shortcuts

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

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.

Menubar with a submenu

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 (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 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:

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:

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

Scoped Personalization

<x-wirekit::menubar scope="editor-toolbar">
    ...
</x-wirekit::menubar>
'personalizations' => [
    'menubar' => [
        'editor-toolbar' => [
            'base' => 'border-b-2',
        ],
    ],
],

Further Reading

Was this page helpful?

Thanks — that helps.

Voting requires cookies or local storage. What we store