Menubar

A horizontal menu bar component based on Radix Vue Menubar primitives. Supports multi-level nested submenus, keyboard navigation, icons, shortcuts, groups, and ARIA accessibility.

Component Features

  • 📋 Nested Submenus: Supports infinite levels of nested submenus, suitable for complex hierarchical structures.
  • ⌨️ Keyboard Navigation: Full keyboard support including arrow keys, Enter, Escape, and typeahead.
  • 🏷️ Shortcuts Display: Configure shortcut key display for menu items to enhance usability.
  • 🎨 Theme Customization: Supports global theme customization based on BrConfigProvider, and local style overrides via TailwindCSS.
  • Accessibility: Built on Radix Vue Menubar with full ARIA support including proper roles, focus management, and screen reader announcements.

Basic Usage

The most basic menubar with top-level menus and dropdown items.

<script setup lang="ts">
import {
  BrMenubar,
  BrMenubarMenu,
  BrMenubarTrigger,
  BrMenubarContent,
  BrMenubarItem,
  BrMenubarSeparator,
} from '@breezeui/vue'
</script>

<template>
  <BrMenubar>
    <BrMenubarMenu>
      <BrMenubarTrigger>File</BrMenubarTrigger>
      <BrMenubarContent>
        <BrMenubarItem>New Tab</BrMenubarItem>
        <BrMenubarItem>New Window</BrMenubarItem>
        <BrMenubarSeparator />
        <BrMenubarItem>Save</BrMenubarItem>
        <BrMenubarItem>Save As...</BrMenubarItem>
        <BrMenubarSeparator />
        <BrMenubarItem>Print</BrMenubarItem>
      </BrMenubarContent>
    </BrMenubarMenu>

    <BrMenubarMenu>
      <BrMenubarTrigger>Edit</BrMenubarTrigger>
      <BrMenubarContent>
        <BrMenubarItem>Undo</BrMenubarItem>
        <BrMenubarItem>Redo</BrMenubarItem>
        <BrMenubarSeparator />
        <BrMenubarItem>Cut</BrMenubarItem>
        <BrMenubarItem>Copy</BrMenubarItem>
        <BrMenubarItem>Paste</BrMenubarItem>
      </BrMenubarContent>
    </BrMenubarMenu>

    <BrMenubarMenu>
      <BrMenubarTrigger>View</BrMenubarTrigger>
      <BrMenubarContent>
        <BrMenubarItem>Zoom In</BrMenubarItem>
        <BrMenubarItem>Zoom Out</BrMenubarItem>
        <BrMenubarItem>Reset Zoom</BrMenubarItem>
        <BrMenubarSeparator />
        <BrMenubarItem>Fullscreen</BrMenubarItem>
      </BrMenubarContent>
    </BrMenubarMenu>
  </BrMenubar>
</template>

Nested Submenus and Shortcuts

Supports multi-level nested submenus via BrMenubarSub / BrMenubarSubTrigger / BrMenubarSubContent, and shortcut display via the shortcut prop.

<script setup lang="ts">
import {
  BrMenubar,
  BrMenubarMenu,
  BrMenubarTrigger,
  BrMenubarContent,
  BrMenubarItem,
  BrMenubarSeparator,
  BrMenubarSub,
  BrMenubarSubTrigger,
  BrMenubarSubContent,
} from '@breezeui/vue'
import { Save, File, Download } from 'lucide-vue-next'
</script>

<template>
  <BrMenubar>
    <BrMenubarMenu>
      <BrMenubarTrigger>File</BrMenubarTrigger>
      <BrMenubarContent>
        <BrMenubarItem>
          <File class="mr-2 h-4 w-4" />
          New File
        </BrMenubarItem>
        <BrMenubarSeparator />
        <BrMenubarSub>
          <BrMenubarSubTrigger>
            <Save class="mr-2 h-4 w-4" />
            Save As
          </BrMenubarSubTrigger>
          <BrMenubarSubContent>
            <BrMenubarItem>PDF</BrMenubarItem>
            <BrMenubarItem>PNG</BrMenubarItem>
            <BrMenubarItem>SVG</BrMenubarItem>
            <BrMenubarSeparator />
            <BrMenubarSub>
              <BrMenubarSubTrigger>More Formats</BrMenubarSubTrigger>
              <BrMenubarSubContent>
                <BrMenubarItem>JSON</BrMenubarItem>
                <BrMenubarItem>XML</BrMenubarItem>
                <BrMenubarItem>CSV</BrMenubarItem>
              </BrMenubarSubContent>
            </BrMenubarSub>
          </BrMenubarSubContent>
        </BrMenubarSub>
        <BrMenubarSeparator />
        <BrMenubarItem>
          <Download class="mr-2 h-4 w-4" />
          Export
        </BrMenubarItem>
      </BrMenubarContent>
    </BrMenubarMenu>

    <BrMenubarMenu>
      <BrMenubarTrigger>Edit</BrMenubarTrigger>
      <BrMenubarContent>
        <BrMenubarItem shortcut="⌘Z">Undo</BrMenubarItem>
        <BrMenubarItem shortcut="⇧⌘Z">Redo</BrMenubarItem>
        <BrMenubarSeparator />
        <BrMenubarItem shortcut="⌘X">Cut</BrMenubarItem>
        <BrMenubarItem shortcut="⌘C">Copy</BrMenubarItem>
        <BrMenubarItem shortcut="⌘V">Paste</BrMenubarItem>
      </BrMenubarContent>
    </BrMenubarMenu>
  </BrMenubar>
</template>

Complex Example

A complex application scenario combining icons, shortcuts, separators, groups, labels, disabled states, and custom styles.

<script setup lang="ts">
import {
  BrMenubar,
  BrMenubarMenu,
  BrMenubarTrigger,
  BrMenubarContent,
  BrMenubarItem,
  BrMenubarSeparator,
  BrMenubarGroup,
  BrMenubarLabel,
} from '@breezeui/vue'
import {
  User,
  Mail,
  Settings,
  Plus,
  FolderOpen,
  Save,
  Scissors,
  Copy,
  Clipboard,
  Search,
} from 'lucide-vue-next'
</script>

<template>
  <BrMenubar>
    <BrMenubarMenu>
      <BrMenubarTrigger>File</BrMenubarTrigger>
      <BrMenubarContent>
        <BrMenubarItem shortcut="⌘N">
          <Plus class="mr-2 h-4 w-4" />
          New File
        </BrMenubarItem>
        <BrMenubarItem shortcut="⌘O">
          <FolderOpen class="mr-2 h-4 w-4" />
          Open
        </BrMenubarItem>
        <BrMenubarSeparator />
        <BrMenubarItem shortcut="⌘S">
          <Save class="mr-2 h-4 w-4" />
          Save
        </BrMenubarItem>
        <BrMenubarSeparator />
        <BrMenubarItem shortcut="⌘Q">
          Quit
        </BrMenubarItem>
      </BrMenubarContent>
    </BrMenubarMenu>

    <BrMenubarMenu>
      <BrMenubarTrigger>Edit</BrMenubarTrigger>
      <BrMenubarContent>
        <BrMenubarItem shortcut="⌘X">
          <Scissors class="mr-2 h-4 w-4" />
          Cut
        </BrMenubarItem>
        <BrMenubarItem shortcut="⌘C">
          <Copy class="mr-2 h-4 w-4" />
          Copy
        </BrMenubarItem>
        <BrMenubarItem shortcut="⌘V">
          <Clipboard class="mr-2 h-4 w-4" />
          Paste
        </BrMenubarItem>
        <BrMenubarSeparator />
        <BrMenubarItem shortcut="⌘F">
          <Search class="mr-2 h-4 w-4" />
          Find
        </BrMenubarItem>
      </BrMenubarContent>
    </BrMenubarMenu>

    <BrMenubarMenu>
      <BrMenubarTrigger>Account</BrMenubarTrigger>
      <BrMenubarContent>
        <BrMenubarGroup>
          <BrMenubarLabel>Profile</BrMenubarLabel>
          <BrMenubarItem>
            <User class="mr-2 h-4 w-4" />
            View Profile
          </BrMenubarItem>
          <BrMenubarItem>Edit Profile</BrMenubarItem>
        </BrMenubarGroup>
        <BrMenubarSeparator />
        <BrMenubarGroup>
          <BrMenubarLabel>Communication</BrMenubarLabel>
          <BrMenubarItem>
            <Mail class="mr-2 h-4 w-4" />
            Inbox
          </BrMenubarItem>
          <BrMenubarItem disabled>
            <Mail class="mr-2 h-4 w-4" />
            Notifications (Coming Soon)
          </BrMenubarItem>
        </BrMenubarGroup>
        <BrMenubarSeparator />
        <BrMenubarItem>
          <Settings class="mr-2 h-4 w-4" />
          Settings
        </BrMenubarItem>
      </BrMenubarContent>
    </BrMenubarMenu>

    <BrMenubarMenu>
      <BrMenubarTrigger disabled>Disabled</BrMenubarTrigger>
      <BrMenubarContent>
        <BrMenubarItem>Should not appear</BrMenubarItem>
      </BrMenubarContent>
    </BrMenubarMenu>
  </BrMenubar>
</template>

Theme Customization

Combined with BrConfigProvider, you can globally override the default styles of the component, such as modifying border radius, hover state colors, menu shadows, etc. At the same time, styles can be overridden locally via TailwindCSS.

<script setup lang="ts">
import {
  BrMenubar,
  BrMenubarMenu,
  BrMenubarTrigger,
  BrMenubarContent,
  BrMenubarItem,
  BrMenubarSeparator,
  BrConfigProvider,
} from '@breezeui/vue'
</script>

<template>
  <BrConfigProvider
    :theme="{
      light: {
        radius: '1rem',
        primary: '220 90% 56%',
        popover: '0 0% 100%',
        'popover-foreground': '240 10% 3.9%',
      },
      dark: {
        radius: '1rem',
        primary: '220 90% 56%',
        popover: '240 10% 3.9%',
        'popover-foreground': '0 0% 98%',
      }
    }"
  >
    <BrMenubar class="border-primary/20 shadow-md">
      <BrMenubarMenu>
        <BrMenubarTrigger>File</BrMenubarTrigger>
        <BrMenubarContent class="border-primary/20 shadow-xl">
          <BrMenubarItem class="focus:bg-primary focus:text-primary-foreground">New File</BrMenubarItem>
          <BrMenubarItem>Open</BrMenubarItem>
          <BrMenubarSeparator />
          <BrMenubarItem>Save</BrMenubarItem>
        </BrMenubarContent>
      </BrMenubarMenu>

      <BrMenubarMenu>
        <BrMenubarTrigger>Edit</BrMenubarTrigger>
        <BrMenubarContent class="border-primary/20 shadow-xl">
          <BrMenubarItem class="focus:bg-primary focus:text-primary-foreground">Undo</BrMenubarItem>
          <BrMenubarItem>Redo</BrMenubarItem>
        </BrMenubarContent>
      </BrMenubarMenu>
    </BrMenubar>
  </BrConfigProvider>
</template>

API Reference

BrMenubar

PropTypeDefaultDescription
modelValue (v-model)string-The value of the active menu
defaultValuestring-The value of the menu that should be open by default
dir'ltr' | 'rtl''ltr'Reading direction
loopbooleanfalseWhether to loop keyboard navigation

BrMenubarMenu

Wraps a single top-level menu (trigger + content pair), no additional props required.

BrMenubarTrigger

PropTypeDefaultDescription
classany-Custom class name
disabledbooleanfalseWhether the trigger is disabled
asChildbooleanfalseMerge props onto child element
textValuestring-Text value for typeahead

BrMenubarContent

PropTypeDefaultDescription
classany-Custom class name
sideOffsetnumber4Distance from the trigger
align'start' | 'center' | 'end''start'Alignment relative to trigger

BrMenubarItem

PropTypeDefaultDescription
classany-Custom class name
disabledbooleanfalseWhether the item is disabled
insetbooleanfalseWhether to include left indentation (for icon alignment)
shortcutstring-Shortcut text (e.g. "⌘K")
textValuestring-Text value for typeahead

Events: @select — Fired when the item is selected.

BrMenubarSeparator

PropTypeDefaultDescription
classany-Custom class name

BrMenubarSub

Root container for nested submenus, no additional props required.

BrMenubarSubTrigger

PropTypeDefaultDescription
classany-Custom class name
disabledbooleanfalseWhether the sub-trigger is disabled
insetbooleanfalseWhether to include left indentation

BrMenubarSubContent

PropTypeDefaultDescription
classany-Custom class name

BrMenubarGroup

PropTypeDefaultDescription
classany-Custom class name

BrMenubarLabel

PropTypeDefaultDescription
classany-Custom class name
insetbooleanfalseWhether to include left indentation