Overlays

DropdownMenu

A trigger-activated menu of grouped, possibly nested actions, with optional avatars/badges.

vue
<UiDropdownMenu />

Options

One block per prop — what it does, and what it looks like set.

Items

items is a flat array is one group. Nest arrays instead and each becomes a group, separated by a divider.

Disabled

disabled is the trigger stops opening the menu at all.

Default open

defaultOpen starts the menu open when it manages its own state. It's a narrow tool: a menu that opens on mount covers whatever is beneath it before anybody asked for it.

Open

Pass it — usually as v-model:open — when something outside the menu has to open or close it.

Open state: false

Content

content sets where the panel sits relative to the trigger — side, alignment and offset.

Match trigger width

matchTriggerWidth stretches the panel to the trigger's width — what a select-like trigger wants, so the button and the list read as one control rather than two.

matchTriggerWidth is what makes it work as a select-like dropdown; without it the menu sizes to its own content, not the trigger.


Examples

The component in real use: compositions that answer "how do I build X with this", rather than one prop at a time.

Item color

An item can carry its own color, which is how a destructive action reads as one.

Icon color

Pass icon as { name, color, fill } to color just the icon and leave the row's text alone — unlike the item's own color, which tints the whole row. It works on label rows and inside submenus too, and fill swaps in the icon's filled variant where one exists. An icon without a color stays toned.

Checkbox items

type: 'checkbox' turns an item into a toggle that keeps the menu open.

Nested submenu

Give an item children and it opens a submenu instead of firing.

This component has multiple root nodes (the trigger, plus teleported menu/submenu panels), so Vue's automatic attrs/class fallthrough doesn't apply — a class you pass is forwarded manually onto the trigger, but don't expect it to land anywhere else.

Hovering an item with children opens a submenu after a short delay; clicking outside either panel closes both.

Team switcher

A trigger built out of a subtle Card rendered as a button — avatar, label and a text-muted caret, the same caret the Select trigger carries — with items holding avatars of their own and matchTriggerWidth so the panel lands squarely under it. Binding v-model:open is what lets the caret flip while the menu is open. It's the header half of the Sidebar page's team switcher, lifted out of the sidebar — and if that's all you want, TeamSwitcher is this already built, with three variants and a collapsed state.


API Reference

Generated from the component's source — props, slots and emits as the component actually declares them.

Props

Prop
Type
Default
Description
DropdownMenuItem[] | DropdownMenuItem[][]
—
The menu items to display, either as a flat array or grouped into arrays separated by dividers.
boolean
false
Prevents the dropdown menu from opening.
boolean
false
Whether the menu is open first when uncontrolled.
boolean
—
Controls whether the menu is open. Omit this to let the menu manage its own state internally (starting from `defaultOpen`); pass it to fully control visibility yourself.
DropdownMenuContentProps
{ align: 'start', side: 'bottom', sideOffset: 8 }
Positioning options for the menu content, such as alignment, side, and offset.
boolean
false
Makes the menu content exactly as wide as its trigger, instead of sizing to its own content.

Slots

Slot
default

Emits

Event
Payload
Description
update:open
[value: boolean]
—

Types

ts
interface DropdownMenuItem {
    label?: string;

    /**
     * The row's icon: an icon name, or `{ name, color, fill }` to also tint just the icon
     * (independent of `color`, which tints the whole row) or render its filled variant.
     */
    icon?: string | MenuItemIcon;
    status?: "online" | "offline" | "away" | "dnd" | "busy";
    avatar?: {
        src?: string;
        alt?: string;
        firstName?: string;
        lastName?: string;
        status?: "online" | "offline" | "away" | "dnd" | "busy";
        shape?: "circle" | "square";
    };
    badge?: {
        text?: number | string;
        color?: "primary" | "secondary" | "success" | "warning" | "error" | "info" | "pending" | "neutral";
    };
    kbds?: Array<string | { value?: string }>;
    type?: "link" | "label" | "separator" | "checkbox";
    color?: "error" | "primary" | "secondary" | "success" | "info" | "warning" | "pending" | "neutral";
    checked?: boolean;
    disabled?: boolean;
    onSelect?: (e: Event) => void;
    onUpdateChecked?: (checked: boolean) => void;
    children?: DropdownMenuItem[] | DropdownMenuItem[][];
    class?: any;
    to?: string;
    target?: string;
}
ts
interface DropdownMenuContentProps {
    align?: "start" | "center" | "end";
    side?: "bottom" | "top";
    sideOffset?: number;
}
ts
interface MenuItemIcon {
    /**
     * Name of the icon to render, same as the `icon` prop of `UiIcon`.
     */
    name: string;

    /**
     * Colors just the icon, independent of the item's `color` (which tints the whole row) or, in a
     * select, of whether the option is selected.
     */
    color?: "error" | "primary" | "secondary" | "success" | "info" | "warning" | "pending" | "neutral";

    /**
     * Render the icon's filled variant. Only some icons ship one — the rest ignore this.
     */
    fill?: boolean;
}