Components / Overlays

DropdownMenu

A keyboard accessible list of actions.

Preview

Use cases

Row actions

Offer several commands without crowding each row.

Persistent choices

Use checkbox items for menu choices that stay selected after the menu closes.

Usage example

Vue
<script setup lang="ts">
import DropdownMenu from './components/ui/dropdown-menu/DropdownMenu.vue'
import DropdownMenuTrigger from './components/ui/dropdown-menu/DropdownMenuTrigger.vue'
import DropdownMenuContent from './components/ui/dropdown-menu/DropdownMenuContent.vue'
import DropdownMenuItem from './components/ui/dropdown-menu/DropdownMenuItem.vue'
import DropdownMenuSeparator from './components/ui/dropdown-menu/DropdownMenuSeparator.vue'
function runAction(action: { id: string }) { console.log(action.id) }
</script>

<template>
  <DropdownMenu align="end" :width="240" @select="runAction">
    <DropdownMenuTrigger aria-label="Open account menu">•••</DropdownMenuTrigger>
    <DropdownMenuContent aria-label="Account actions">
      <div class="px-3 py-2">
        <p class="font-semibold">Acme Studio</p>
        <p class="text-xs text-muted-foreground">Pro workspace</p>
      </div>
      <DropdownMenuSeparator />
      <DropdownMenuItem id="profile" label="View profile" shortcut="⇧⌘P">
        <template #prefix><span aria-hidden="true">◉</span></template>
        View profile
      </DropdownMenuItem>
      <DropdownMenuItem id="settings" label="Settings" shortcut="⌘," />
      <DropdownMenuItem id="duplicate" label="Duplicate workspace" />
      <DropdownMenuSeparator />
      <DropdownMenuItem id="archive" label="Archive workspace" destructive />
    </DropdownMenuContent>
  </DropdownMenu>
</template>

More examples

Project actions

A selected item emits its ID to application code.

Project actions
<script setup lang="ts">
import DropdownMenu from './components/ui/dropdown-menu/DropdownMenu.vue'
import DropdownMenuTrigger from './components/ui/dropdown-menu/DropdownMenuTrigger.vue'
import DropdownMenuContent from './components/ui/dropdown-menu/DropdownMenuContent.vue'
import DropdownMenuItem from './components/ui/dropdown-menu/DropdownMenuItem.vue'
import DropdownMenuSeparator from './components/ui/dropdown-menu/DropdownMenuSeparator.vue'
</script>
<template>
  <DropdownMenu @select="$emit('action', $event.id)">
    <DropdownMenuTrigger>Project actions</DropdownMenuTrigger>
    <DropdownMenuContent aria-label="Project actions">
      <DropdownMenuItem id="rename" label="Rename">Rename</DropdownMenuItem>
      <DropdownMenuSeparator />
      <DropdownMenuItem id="archive" label="Archive" destructive>Archive</DropdownMenuItem>
    </DropdownMenuContent>
  </DropdownMenu>
</template>

Checkbox option

The checked model remains in application state.

Checkbox option
<script setup lang="ts">
import { ref } from 'vue'
import DropdownMenu from './components/ui/dropdown-menu/DropdownMenu.vue'
import DropdownMenuTrigger from './components/ui/dropdown-menu/DropdownMenuTrigger.vue'
import DropdownMenuContent from './components/ui/dropdown-menu/DropdownMenuContent.vue'
import DropdownMenuCheckboxItem from './components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue'
const showArchived = ref(false)
</script>
<template>
  <DropdownMenu>
    <DropdownMenuTrigger>Display options</DropdownMenuTrigger>
    <DropdownMenuContent aria-label="Display options">
      <DropdownMenuCheckboxItem id="archived" label="Show archived" v-model:checked="showArchived">Show archived</DropdownMenuCheckboxItem>
    </DropdownMenuContent>
  </DropdownMenu>
</template>

Key API

The most useful props, models, slots, events, and methods for this component.

Key API for DropdownMenu
NameTypeDefault or requirement
itemsDropdownMenuItemData[]optional
DropdownMenuContent aria-labelstringrequired for unnamed menu
selectevent with selected item
Checkbox / Radio / Submenu partscompound childrenoptional
Item #prefix / #suffixslots at item edgesoptional
align / sidestart | center | end / top | bottomstart / bottom

Items, checkbox/radio choices, groups, and nested submenus share roving focus, typeahead, RTL-aware arrows, and layer-local Escape handling.

Implementation notes

  • Selection emits an action; application code owns the side effect.
  • The shortcut prop displays a hint and does not register a global keyboard shortcut.

Accessibility and localization

  • Name the content menu and give each item a stable ID and readable label.
  • Arrow keys and typeahead skip disabled items; Escape restores trigger focus.
Weini UIDesign system · Vue component library · Free and public