Dropdown Menu

An enterprise-level dropdown menu component based on BrConfigProvider for global theme configuration. It supports multiple directions, nested submenus, and custom trigger methods.

Component Features

  • 🛠️ Multi-direction Popover: Supports popping out from top, bottom, left, and right directions, auto-adjusting to fit screen edges.
  • 📋 Nested Submenus: Supports infinite levels of nested submenus, suitable for complex hierarchical structures.
  • ⌨️ Shortcuts Support: Allows configuring shortcut keys for menu items to enhance keyboard operation experience.
  • 🖱️ Multiple Triggers: Supports various trigger methods such as click, hover, and contextmenu.
  • 🎨 Theme Customization: Supports global theme customization based on BrConfigProvider, and local style overrides via TailwindCSS.

Basic Usage

The most basic dropdown menu display.

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrDropdownMenuSeparator,
  BrButton
} from '@breezeui/vue'
</script>

<template>
  <BrDropdownMenu>
    <BrDropdownMenuTrigger as-child>
      <BrButton variant="outline">Open Menu</BrButton>
    </BrDropdownMenuTrigger>
    <BrDropdownMenuContent>
      <BrDropdownMenuItem>Profile</BrDropdownMenuItem>
      <BrDropdownMenuItem>Billing</BrDropdownMenuItem>
      <BrDropdownMenuItem>Settings</BrDropdownMenuItem>
      <BrDropdownMenuSeparator />
      <BrDropdownMenuItem>Logout</BrDropdownMenuItem>
    </BrDropdownMenuContent>
  </BrDropdownMenu>
</template>

Position

Supports align and side properties to control the pop-up position, supporting 12 different directions.

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrButton
} from '@breezeui/vue'

const positions = [
  [
    { label: 'Top Start', side: 'top', align: 'start' },
    { label: 'Top', side: 'top', align: 'center' },
    { label: 'Top End', side: 'top', align: 'end' },
  ],
  [
    { label: 'Right Start', side: 'right', align: 'start' },
    { label: 'Right', side: 'right', align: 'center' },
    { label: 'Right End', side: 'right', align: 'end' },
  ],
  [
    { label: 'Bottom End', side: 'bottom', align: 'end' },
    { label: 'Bottom', side: 'bottom', align: 'center' },
    { label: 'Bottom Start', side: 'bottom', align: 'start' },
  ],
  [
    { label: 'Left End', side: 'left', align: 'end' },
    { label: 'Left', side: 'left', align: 'center' },
    { label: 'Left Start', side: 'left', align: 'start' },
  ]
] as const
</script>

<template>
  <div class="flex flex-col items-center gap-4 py-8">
    <div v-for="(row, i) in positions" :key="i" class="flex flex-wrap justify-center gap-4">
      <BrDropdownMenu v-for="pos in row" :key="pos.label">
        <BrDropdownMenuTrigger as-child>
          <BrButton variant="outline" class="w-[120px]">{{ pos.label }}</BrButton>
        </BrDropdownMenuTrigger>
        <BrDropdownMenuContent :side="pos.side" :align="pos.align">
          <BrDropdownMenuItem>Option 1</BrDropdownMenuItem>
          <BrDropdownMenuItem>Option 2</BrDropdownMenuItem>
          <BrDropdownMenuItem>Option 3</BrDropdownMenuItem>
        </BrDropdownMenuContent>
      </BrDropdownMenu>
    </div>
  </div>
</template>

Complex Example

A complex application scenario combining icons, shortcuts, separators, nested submenus, disabled states, custom styles (like red highlight for destructive actions).

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrDropdownMenuSeparator,
  BrDropdownMenuSub,
  BrDropdownMenuSubTrigger,
  BrDropdownMenuSubContent,
  BrButton
} from '@breezeui/vue'
import {
  Cloud,
  CreditCard,
  Github,
  Keyboard,
  LifeBuoy,
  LogOut,
  Mail,
  MessageSquare,
  Plus,
  PlusCircle,
  Settings,
  User,
  UserPlus,
} from 'lucide-vue-next'
</script>

<template>
  <BrDropdownMenu>
    <BrDropdownMenuTrigger as-child>
      <BrButton variant="outline">Complex Menu Example</BrButton>
    </BrDropdownMenuTrigger>
    <BrDropdownMenuContent class="w-56" align="end" :side-offset="8">
      <div class="px-2 py-1.5 text-sm font-normal">
        <div class="flex flex-col space-y-1">
          <p class="text-sm font-medium leading-none">breezeui</p>
          <p class="text-xs leading-none text-muted-foreground">
            breezeui@example.com
          </p>
        </div>
      </div>
      <BrDropdownMenuSeparator />
      
      <BrDropdownMenuItem shortcut="⇧⌘P">
        <User class="mr-2 h-4 w-4" />
        <span>Profile Page</span>
      </BrDropdownMenuItem>
      <BrDropdownMenuItem shortcut="⌘B">
        <CreditCard class="mr-2 h-4 w-4" />
        <span>Billing Info</span>
      </BrDropdownMenuItem>
      <BrDropdownMenuItem shortcut="⌘S">
        <Settings class="mr-2 h-4 w-4" />
        <span>System Settings</span>
      </BrDropdownMenuItem>
      <BrDropdownMenuItem shortcut="⌘K">
        <Keyboard class="mr-2 h-4 w-4" />
        <span>Shortcut Configuration</span>
      </BrDropdownMenuItem>
      
      <BrDropdownMenuSeparator />
      
      <BrDropdownMenuSub>
        <BrDropdownMenuSubTrigger>
          <UserPlus class="mr-2 h-4 w-4" />
          <span>Invite Team Members</span>
        </BrDropdownMenuSubTrigger>
        <BrDropdownMenuSubContent>
          <BrDropdownMenuItem>
            <Mail class="mr-2 h-4 w-4" />
            <span>Via Email</span>
          </BrDropdownMenuItem>
          <BrDropdownMenuItem>
            <MessageSquare class="mr-2 h-4 w-4" />
            <span>Via SMS</span>
          </BrDropdownMenuItem>
          <BrDropdownMenuSeparator />
          <BrDropdownMenuItem>
            <PlusCircle class="mr-2 h-4 w-4" />
            <span>More Invite Options...</span>
          </BrDropdownMenuItem>
        </BrDropdownMenuSubContent>
      </BrDropdownMenuSub>
      
      <BrDropdownMenuItem>
        <Plus class="mr-2 h-4 w-4" />
        <span>New Team</span>
      </BrDropdownMenuItem>
      
      <BrDropdownMenuSeparator />
      
      <BrDropdownMenuItem>
        <Github class="mr-2 h-4 w-4" />
        <span>GitHub Repository</span>
      </BrDropdownMenuItem>
      <BrDropdownMenuItem>
        <LifeBuoy class="mr-2 h-4 w-4" />
        <span>Support</span>
      </BrDropdownMenuItem>
      <BrDropdownMenuItem disabled>
        <Cloud class="mr-2 h-4 w-4" />
        <span>API Service (Under Maintenance)</span>
      </BrDropdownMenuItem>
      
      <BrDropdownMenuSeparator />
      
      <BrDropdownMenuItem shortcut="⇧⌘Q" class="text-destructive focus:bg-destructive focus:text-destructive-foreground">
        <LogOut class="mr-2 h-4 w-4" />
        <span>Logout</span>
      </BrDropdownMenuItem>
    </BrDropdownMenuContent>
  </BrDropdownMenu>
</template>

Nested Submenus and Shortcuts

Supports multi-level nested submenus and configuring keyboard shortcuts via the shortcut prop.

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrDropdownMenuSeparator,
  BrDropdownMenuSub,
  BrDropdownMenuSubTrigger,
  BrDropdownMenuSubContent,
  BrButton
} from '@breezeui/vue'
</script>

<template>
  <BrDropdownMenu>
    <BrDropdownMenuTrigger as-child>
      <BrButton variant="outline">User Action</BrButton>
    </BrDropdownMenuTrigger>
    <BrDropdownMenuContent class="w-56">
      <BrDropdownMenuItem shortcut="⇧⌘P">Profile Page</BrDropdownMenuItem>
      <BrDropdownMenuItem shortcut="⌘B">Billing</BrDropdownMenuItem>
      <BrDropdownMenuItem shortcut="⌘S">Settings</BrDropdownMenuItem>
      <BrDropdownMenuSeparator />
      <BrDropdownMenuSub>
        <BrDropdownMenuSubTrigger>Invite User</BrDropdownMenuSubTrigger>
        <BrDropdownMenuSubContent>
          <BrDropdownMenuItem>Via Email</BrDropdownMenuItem>
          <BrDropdownMenuItem>Via SMS</BrDropdownMenuItem>
          <BrDropdownMenuSeparator />
          <BrDropdownMenuItem>More Options...</BrDropdownMenuItem>
        </BrDropdownMenuSubContent>
      </BrDropdownMenuSub>
      <BrDropdownMenuSeparator />
      <BrDropdownMenuItem shortcut="⇧⌘Q" disabled>Logout</BrDropdownMenuItem>
    </BrDropdownMenuContent>
  </BrDropdownMenu>
</template>

Custom Trigger Methods (Hover/ContextMenu)

Supports click, hover, and contextmenu trigger methods, which can be configured via the trigger prop.

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrDropdownMenuSeparator,
  BrButton
} from '@breezeui/vue'
</script>

<template>
  <div class="flex gap-4">
    <!-- Hover Trigger -->
    <BrDropdownMenu trigger="hover">
      <BrDropdownMenuTrigger as-child>
        <BrButton variant="outline">Hover to expand</BrButton>
      </BrDropdownMenuTrigger>
      <BrDropdownMenuContent>
        <BrDropdownMenuItem>Option 1</BrDropdownMenuItem>
        <BrDropdownMenuItem>Option 2</BrDropdownMenuItem>
      </BrDropdownMenuContent>
    </BrDropdownMenu>

    <!-- Right-click Trigger -->
    <BrDropdownMenu trigger="contextmenu">
      <BrDropdownMenuTrigger as-child>
        <div class="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed text-sm">
          Right-click in this area
        </div>
      </BrDropdownMenuTrigger>
      <BrDropdownMenuContent>
        <BrDropdownMenuItem>Refresh</BrDropdownMenuItem>
        <BrDropdownMenuItem>Save As...</BrDropdownMenuItem>
        <BrDropdownMenuSeparator />
        <BrDropdownMenuItem class="text-destructive">Delete</BrDropdownMenuItem>
      </BrDropdownMenuContent>
    </BrDropdownMenu>
  </div>
</template>

Form Integration

Typical application in form operations or table row actions.

<script setup lang="ts">
import {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrDropdownMenuSeparator,
  BrButton,
  BrForm,
  BrFormItem
} from '@breezeui/vue'
import { ChevronDown } from 'lucide-vue-next'
</script>

<template>
  <BrForm>
    <BrFormItem label="Action">
      <BrDropdownMenu>
        <BrDropdownMenuTrigger as-child>
          <BrButton variant="outline">Action <ChevronDown class="ml-2 h-4 w-4" /></BrButton>
        </BrDropdownMenuTrigger>
        <BrDropdownMenuContent>
          <BrDropdownMenuItem>Edit</BrDropdownMenuItem>
          <BrDropdownMenuItem>Copy</BrDropdownMenuItem>
          <BrDropdownMenuSeparator />
          <BrDropdownMenuItem class="text-destructive">Delete</BrDropdownMenuItem>
        </BrDropdownMenuContent>
      </BrDropdownMenu>
    </BrFormItem>
  </BrForm>
</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 {
  BrDropdownMenu,
  BrDropdownMenuTrigger,
  BrDropdownMenuContent,
  BrDropdownMenuItem,
  BrButton,
  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%',
      }
    }"
  >
    <BrDropdownMenu>
      <BrDropdownMenuTrigger as-child>
        <BrButton>Custom Theme Dropdown Menu</BrButton>
      </BrDropdownMenuTrigger>
      <!-- Local Override Style Example -->
      <BrDropdownMenuContent class="border-primary/20 shadow-xl">
        <BrDropdownMenuItem class="focus:bg-primary focus:text-primary-foreground">
          Highlight Option
        </BrDropdownMenuItem>
        <BrDropdownMenuItem>Normal Option</BrDropdownMenuItem>
      </BrDropdownMenuContent>
    </BrDropdownMenu>
  </BrConfigProvider>
</template>

API Reference

BrDropdownMenu

PropTypeDefaultDescription
open (v-model)boolean-Controls the open state of the menu
defaultOpenbooleanfalseDefault open state
dir'ltr' | 'rtl''ltr'Text reading direction
trigger'click' | 'hover' | 'contextmenu' | Array'click'Trigger method configuration
openDelaynumber200Open delay in ms when hover triggered
closeDelaynumber300Close delay in ms when hover triggered

BrDropdownMenuContent

PropTypeDefaultDescription
classany-Custom class name
side'top' | 'right' | 'bottom' | 'left''bottom'The preferred side of the menu to render against
sideOffsetnumber4The distance in pixels from the trigger
align'start' | 'center' | 'end''center'The preferred alignment against the trigger
alignOffsetnumber0Alignment offset

BrDropdownMenuItem

PropTypeDefaultDescription
disabledbooleanfalseWhether the item is disabled
shortcutstring-Shortcut text (e.g. "⌘K")
insetbooleanfalseWhether to include left indentation (for icon alignment)

BrDropdownMenuSub

Root container for nested submenus, no additional props required.

BrDropdownMenuEmpty / BrDropdownMenuLoading

Used to display empty or loading states.

PropTypeDefaultDescription
textstring'No data' / 'Loading...'Prompt text