Skip to content

DropdownMenu ​

Menu component for use inside Dropdown. Displays a list of clickable items with keyboard navigation support.

Import ​

typescript
import { Dropdown, DropdownMenu } from 'vuiii'

Basic Usage ​

vue
<script setup>
const menuItems = [
  { label: 'Edit', icon: 'pencil' },
  { label: 'Duplicate', icon: 'document-duplicate' },
  { label: 'Delete', icon: 'trash' },
]
</script>

<template>
  <Dropdown label="Actions">
    <DropdownMenu :items="menuItems" @itemClick="handleClick" />
  </Dropdown>
</template>

Custom Item Rendering ​

Use the item or itemLabel slot to customize how items are displayed:

vue
<DropdownMenu :items="users">
  <template #item="{ item, index }">
    <div class="user-item">
      <Avatar :src="item.avatar" />
      <span>{{ item.name }}</span>
    </div>
  </template>
</DropdownMenu>

Props ​

PropTypeDescription
itemsItem[]Array of menu items
cursorIndexnumberIndex of the currently highlighted item (for keyboard navigation)
itemDisabled(item, index) => booleanMarks an item unavailable: renders it disabled and emits no click
itemGroupLabel(item, index) => string | undefinedGroups consecutive items under a heading
listRole'listbox' | 'menu'ARIA role for the list element
listIdstringId of the list element, referenced by a combobox via aria-controls
optionIdPrefixstringPrefix for per-option ids, used for aria-activedescendant

Slots ​

SlotDescription
itemReplaces the whole item, button included. Props: { item, index, cursorIndex }
itemLabelReplaces only the item's label, keeping the button. Props: { item, index, cursorIndex }
groupLabelReplaces a group heading. Props: { label }

Events ​

EventPayloadDescription
item-click{ item, index }Emitted when an item is clicked
item-mouseenter{ item, index }Emitted when mouse enters an item
item-mouseleave{ item, index }Emitted when mouse leaves an item

Disabled Items ​

itemDisabled receives each item and returns whether it is unavailable. Disabled items render as natively disabled buttons, are marked aria-disabled, and emit no item-click.

vue
<DropdownMenu :items="actions" :item-disabled="(action) => !action.allowed" @item-click="run" />

Grouping ​

itemGroupLabel renders a heading wherever the label changes. Items are expected to arrive already ordered by group — a group split across the list renders its heading twice.

vue
<DropdownMenu :items="options" :item-group-label="(option) => option.category">
  <template #groupLabel="{ label }">
    <Icon name="folder" /> {{ label }}
  </template>
</DropdownMenu>

Indices stay contiguous across the headings, so cursorIndex, optionIdPrefix and the emitted payloads keep pointing at the item's position in items, not at its rendered row.

Released under the MIT License.