DropdownMenu
A list of actions or options, triggered by a button.
<template>
<DropdownMenu :items="[[{ label: 'Edit', icon: 'i-lucide-pencil', onSelect: onEdit }], [{ label: 'Delete', icon: 'i-lucide-trash', color: 'error', onSelect: onDelete }]]">
<Button variant="secondary" trailing-icon="i-lucide-chevron-down">Actions</Button>
</DropdownMenu>
</template>Props
| Name | Type | Default |
|---|---|---|
| items | DropdownMenuItem[] | DropdownMenuItem[][] | — |
Slots
| Name | Description |
|---|---|
| default | The trigger. Any element works, but real usage is always a Button — a labeled one with a trailing chevron for most menus, or an icon-only kebab for an overflow menu. |
Usage
Examples
Basic
A grouped menu with a section label and a separator between groups.
const items = [
[
{ type: 'label', label: 'My Account' },
{ label: 'Profile', icon: 'i-lucide-user' },
{ label: 'Billing', icon: 'i-lucide-credit-card' },
],
[
{ label: 'Team', icon: 'i-lucide-users' },
{ label: 'Subscription', icon: 'i-lucide-badge-dollar-sign' },
],
]
<DropdownMenu :items="items">
<Button variant="secondary" trailing-icon="i-lucide-chevron-down">Open</Button>
</DropdownMenu>Submenu
A nested menu opened from a parent item.
const items = [
{ label: 'Profile', icon: 'i-lucide-user' },
{
label: 'Invite users',
icon: 'i-lucide-user-plus',
children: [
{ label: 'Email', icon: 'i-lucide-mail' },
{ label: 'Message', icon: 'i-lucide-message-square' },
{ type: 'separator' },
{ label: 'More...', icon: 'i-lucide-plus-circle' },
],
},
{ label: 'Log out', icon: 'i-lucide-log-out' },
]
<DropdownMenu :items="items">
<Button variant="secondary" trailing-icon="i-lucide-chevron-down">Open</Button>
</DropdownMenu>Shortcuts
Keyboard shortcut hints shown next to each item.
const items = [
{ label: 'Profile', kbds: ['meta', 'P'] },
{ label: 'Billing', kbds: ['meta', 'B'] },
{ label: 'Settings', kbds: ['meta', 'S'] },
{ label: 'Keyboard shortcuts', kbds: ['meta', 'K'] },
]
<DropdownMenu :items="items">
<Button variant="secondary" trailing-icon="i-lucide-chevron-down">Open</Button>
</DropdownMenu>Icons
A leading icon on every item.
const items = [
{ label: 'Profile', icon: 'i-lucide-user' },
{ label: 'Billing', icon: 'i-lucide-credit-card' },
{ label: 'Settings', icon: 'i-lucide-settings' },
{ label: 'Log out', icon: 'i-lucide-log-out' },
]
<DropdownMenu :items="items">
<Button variant="secondary" trailing-icon="i-lucide-chevron-down">Open</Button>
</DropdownMenu>Checkboxes
Independent toggles that stay open after each click.
const showStatusBar = ref(true)
const showActivityBar = ref(false)
const items = computed(() => [
{ type: 'label', label: 'Appearance' },
{ type: 'checkbox', label: 'Status Bar', checked: showStatusBar.value, onUpdateChecked: (c) => showStatusBar.value = c },
{ type: 'checkbox', label: 'Activity Bar', checked: showActivityBar.value, onUpdateChecked: (c) => showActivityBar.value = c },
{ type: 'checkbox', label: 'Panel', disabled: true },
])
<DropdownMenu :items="items">
<Button variant="secondary" trailing-icon="i-lucide-chevron-down">View</Button>
</DropdownMenu>Checkboxes Icons
Checkbox items whose icon reflects their own checked state.
const notifyPush = ref(true)
const notifyEmail = ref(false)
const items = computed(() => [
{ type: 'label', label: 'Notifications' },
{ type: 'checkbox', label: 'Push notifications', icon: notifyPush.value ? 'i-lucide-bell' : 'i-lucide-bell-off', checked: notifyPush.value, onUpdateChecked: (c) => notifyPush.value = c },
{ type: 'checkbox', label: 'Email notifications', icon: notifyEmail.value ? 'i-lucide-mail' : 'i-lucide-mail-x', checked: notifyEmail.value, onUpdateChecked: (c) => notifyEmail.value = c },
])
<DropdownMenu :items="items">
<Button variant="secondary" trailing-icon="i-lucide-chevron-down">Notifications</Button>
</DropdownMenu>Radio Group
Mutually exclusive options, only one selected at a time.
const paymentMethod = ref('card')
// UDropdownMenu has no native radio item type — type: 'checkbox' items that all write to
// the same ref, keyed to their own value, approximate one instead.
const items = computed(() => [
{ type: 'label', label: 'Payment Method' },
{ type: 'checkbox', label: 'Credit Card', checked: paymentMethod.value === 'card', onUpdateChecked: () => paymentMethod.value = 'card' },
{ type: 'checkbox', label: 'PayPal', checked: paymentMethod.value === 'paypal', onUpdateChecked: () => paymentMethod.value = 'paypal' },
{ type: 'checkbox', label: 'Apple Pay', checked: paymentMethod.value === 'apple-pay', onUpdateChecked: () => paymentMethod.value = 'apple-pay' },
])
<DropdownMenu :items="items">
<Button variant="secondary" trailing-icon="i-lucide-chevron-down">Payment Method</Button>
</DropdownMenu>Radio Icons
A radio group with a leading icon per option.
const radioMethod = ref('card')
const items = computed(() => [
{ type: 'label', label: 'Payment Method' },
{ type: 'checkbox', label: 'Credit Card', icon: 'i-lucide-credit-card', checked: radioMethod.value === 'card', onUpdateChecked: () => radioMethod.value = 'card' },
{ type: 'checkbox', label: 'PayPal', icon: 'i-lucide-wallet', checked: radioMethod.value === 'paypal', onUpdateChecked: () => radioMethod.value = 'paypal' },
{ type: 'checkbox', label: 'Apple Pay', icon: 'i-lucide-smartphone', checked: radioMethod.value === 'wallet', onUpdateChecked: () => radioMethod.value = 'wallet' },
])
<DropdownMenu :items="items">
<Button variant="secondary" trailing-icon="i-lucide-chevron-down">Payment Method</Button>
</DropdownMenu>Destructive
A destructive action set apart from the rest of the menu.
const items = [
[
{ type: 'label', label: 'Actions' },
{ label: 'Edit', icon: 'i-lucide-pencil' },
{ label: 'Duplicate', icon: 'i-lucide-copy' },
],
[
{ label: 'Delete', icon: 'i-lucide-trash', color: 'error' },
],
]
<DropdownMenu :items="items">
<Button variant="secondary" trailing-icon="i-lucide-chevron-down">Actions</Button>
</DropdownMenu>Avatar
A user menu opened from an avatar instead of a button.
const items = [
[
{ type: 'label', label: 'Leo Rivera' },
{ label: 'Profile', icon: 'i-lucide-user' },
{ label: 'Settings', icon: 'i-lucide-settings' },
],
[
{ label: 'Log out', icon: 'i-lucide-log-out' },
],
]
<DropdownMenu :items="items" :content="{ align: 'end' }">
<Avatar alt="Leo Rivera" size="sm" />
</DropdownMenu>Complex
Shortcuts, icons, and a submenu combined in one real-world menu.
const items = [
[
{ type: 'label', label: 'My Account' },
{ label: 'Profile', icon: 'i-lucide-user', kbds: ['meta', 'P'] },
{ label: 'Billing', icon: 'i-lucide-credit-card', kbds: ['meta', 'B'] },
{
label: 'Invite users',
icon: 'i-lucide-user-plus',
children: [
{ label: 'Email', icon: 'i-lucide-mail' },
{ label: 'Message', icon: 'i-lucide-message-square' },
],
},
],
[
{ label: 'Log out', icon: 'i-lucide-log-out', kbds: ['shift', 'meta', 'Q'] },
],
]
<DropdownMenu :items="items">
<Button variant="secondary" trailing-icon="i-lucide-chevron-down">Open</Button>
</DropdownMenu>