Menu
Overview
The Menu component family lets you build complex nested menus, including dropdowns and context menus. It provides a data-driven approach using SMenuOptions, SMenuCheckboxOptions, and SMenuRadioOptions for easy configuration of groups, submenus, checkboxes, radio items, separators, shortcuts, and link items. The logic layer reuses @vean/aria/menu with full WAI-ARIA menu semantics and roving-focus keyboard navigation.
Features
- Data-driven compact composition —
SMenuOptions/SMenuCheckboxOptions/SMenuRadioOptionsrecursively render items from anitemsarray; the AriaMenuOptionsCompactowns iteration, default assembly, and submenu recursion. - Full WAI-ARIA menu semantics —
role="menu"/menuitem/menuitemcheckbox/menuitemradio,aria-checked(including'mixed'),aria-haspopup,aria-expanded,aria-controls,aria-disabled. - Full keyboard navigation — roving-focus arrow movement (dir-aware), typeahead character search (skips disabled), Home/End/PageUp/PageDown jumps, Enter/Space selection, Esc close + focus return, Tab loop inside the menu, and submenu open/close arrow keys.
- Floating positioning — built on
@floating-ui/dom(autoUpdate+arrow/flip/hide/limitShift/offset/shift/sizemiddleware) with arrow, placement, sideOffset, and CSS variable forwarding. - Three data shapes — plain
MenuOptionData(icon/shortcut/separator/link/submenu), checkboxMenuCheckboxOptionData(CheckedStateincluding'mixed'), and radioMenuRadioOptionData(AcceptableBooleanValue), each with its own group. - Grouping & separators —
isGroupLabelrenders aMenuGroupLabelheading,separatorrenders a divider, andshortcutrenders a keyboard hint. - Floating lifecycle — dismissable layer (outside pointer / Esc close), Presence (exit animation +
forceMount), body scroll lock, focus scope/trap, and modal mode. - Disabled items — per-item
disabledwithitemProps.disabledfallback (explicit value wins),aria-disabled+tabindex="-1". - Hidden items — per-item
hiddendrops the option (and its whole subtree) from rendering, the active-path search and keyboard navigation; an item whose children are all hidden renders as a leaf. - Aria composition —
MenuRoot/MenuContent/MenuItem/MenuCheckboxItem/MenuRadioItem/MenuSub/MenuGroupexported from@vean/aria/menu, reused by dropdown-menu, context-menu, and menubar.
Component family
SMenuOptions— data-driven list of plain menu items (with submenus/links/separators/shortcuts).SMenuOption— the recursive item component used internally bySMenuOptions(can be used standalone).SMenuCheckboxOptions— a group of checkbox items (v-modelarray /CheckedState).SMenuRadioOptions— a group of radio items (v-modelbound toAcceptableBooleanValue).
Usage
Demos
Basic
API
Aria Layer
27ContextMenuPopup
MenuAnchor
MenuArrow
MenuCheckboxGroup<T extends DefinedValue = DefinedValue>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | T[] | — | The controlled value of the checkbox. Can be bound with v-model. |
defaultValue | T[] | — | The value of the checkbox when it is initially rendered. Use when you do not need to control its value. |
disabled | boolean | false | When `true`, prevents the user from interacting with the checkboxes |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | T[] | Event handler called when the value of the checkbox group changes. |
MenuCheckboxItem
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | CheckedState | — | The controlled checked state of the item. Can be used as `v-model`. |
value | DefinedValue | on | The value given as data when submitted with a `name`. |
disabled | boolean | — | When `true`, prevents the user from interacting with the item. |
textValue | string | — | Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the
item. <br> Use this when the content is complex, or you have non-textual content inside. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
select | Event | Event handler called when the user selects an item (via mouse or keyboard). <br> Calling `event.preventDefault` in
this handler will prevent the menu from closing when selecting that item. |
update:modelValue | CheckedState | Event handler called when the checked state of the item changes. |
MenuCheckboxOptionsCompact<T>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | MenuCheckboxOptionData<T>[] | — | Items rendered by the component. |
groupLabelProps | MenuGroupLabelProps | — | Properties forwarded to the group label element. |
checkboxItemProps | MenuCheckboxItemProps | — | Properties forwarded to the checkbox item element. |
indicatorProps | MenuItemIndicatorProps | — | Properties forwarded to the indicator element. |
shortcutProps | MenuShortcutProps | — | Properties forwarded to the shortcut element. |
separatorProps | MenuSeparatorProps | — | Properties forwarded to the separator element. |
modelValue | T[] | — | The controlled value of the checkbox. Can be bound with v-model. |
defaultValue | T[] | — | The value of the checkbox when it is initially rendered. Use when you do not need to control its value. |
disabled | boolean | false | When `true`, prevents the user from interacting with the checkboxes |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | T[] | Event handler called when the value of the checkbox group changes. |
select | MenuCheckboxOptionData<T>, event: Event | Emitted when select occurs. |
Slots
| Slot Name | Parameters | Description |
|---|---|---|
item | MenuCheckboxOptionData<T> | Custom content for the item slot. |
item-leading | MenuCheckboxOptionData<T> | Custom content for the item leading slot. |
item-trailing | MenuCheckboxOptionData<T> | Custom content for the item trailing slot. |
item-indicator-icon | MenuCheckboxOptionData<T> | Custom content for the item indicator icon slot. |
MenuCheckboxOptionsCompactSelect<T>
Emits
| Emit Name | Parameters | Description |
|---|---|---|
select | MenuCheckboxOptionData<T>, event: Event | Emitted when select occurs. |
MenuContent
Props
| Prop | Type | Default | Description |
|---|---|---|---|
popupProps | MenuPopupProps | — | Properties forwarded to the popup element. |
placement | Placement | undefined | The placement of the floating element.
If used, it will override the `side` and `align` props. |
side | Side | 'bottom' | The preferred side of the trigger to render against when open. Will be reversed when collisions occur and
avoidCollisions is enabled. |
sideOffset | number | 0 | The distance in pixels from the trigger. |
sideFlip | boolean | true | Flip to the opposite side when colliding with boundary. |
align | Align | 'center' | The preferred alignment against the trigger. May change when collisions occur. |
alignOffset | number | 0 | An offset in pixels from the `start` or `end` alignment options. |
alignFlip | boolean | true | Flip alignment when colliding with boundary.
May only occur when `prioritizePosition` is true. |
avoidCollisions | boolean | true | When `true`, overrides the side and align preferences to prevent collisions with boundary edges. |
collisionBoundary | Element | (Element | null)[] | null | [ ] | The element used as the collision boundary. By default this is the viewport, though you can provide additional
element(s) to be included in this check. |
collisionPadding | Padding | 0 | The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for
all sides), or a partial padding object, for example: { top: 20, left: 20 }. |
arrowPadding | number | 0 | The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it
from overflowing the corners. |
hideShiftedArrow | boolean | true | When `true`, hides the arrow when it cannot be centered
to the reference element. |
sticky | 'partial' | 'always' | 'partial' | The sticky behavior on the align axis. `partial` will keep the content in the boundary as long as the trigger is at
least partially in the boundary whilst "always" will keep the content in the boundary regardless. |
hideWhenDetached | boolean | false | Whether to hide the content when the trigger becomes fully occluded. |
positionStrategy | 'fixed' | 'absolute' | 'fixed' | The type of CSS position property to use. |
updatePositionStrategy | 'always' | 'optimized' | 'optimized' | Strategy to update the position of the floating element on every animation frame. |
disableUpdateOnLayoutShift | boolean | false | Whether to disable the update position for the content when the layout shifted. |
prioritizePosition | boolean | false | Force content to be position within the viewport. Might overlap the reference element, which may not be desired. |
reference | ReferenceElement | — | The custom element or virtual element that will be set as the reference to position the floating element. If
provided, it will replace the default anchor element. |
trapFocus | boolean | modal | Whether focus is trapped inside the popup while open (Tab cycles within the layer and body
scroll is locked for modal layers). |
disableHoverableContent | boolean | false | When `true`, hovering the popup closes instead of keeping it open (the grace area is disabled,
so leaving the trigger closes the layer immediately). |
onGracePointerExit | (() => void) | — | Callback invoked when the pointer finally leaves the grace area. Lets an upper layer (e.g.
Tooltip) run area-scoped close logic without registering its own second grace area. |
forceMount | boolean | — | Used to force mounting when more control is needed.
Useful when controlling animation with Vue animation libraries. |
loop | boolean | false | Whether keyboard navigation should loop around |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
escapeKeyDown | KeyboardEvent | Event handler called when the escape key is down. Can be prevented. |
pointerDownOutside | PointerDownOutsideEvent | Event handler called when a `pointerdown` event happens outside of the `DismissableLayer`. Can be prevented. |
focusOutside | FocusOutsideEvent | Event handler called when the focus moves outside of the `DismissableLayer`. Can be prevented. |
interactOutside | PointerDownOutsideEvent | FocusOutsideEvent | Event handler called when an interaction happens outside the `DismissableLayer`. Specifically, when a `pointerdown`
event happens outside or focus moves outside of it. Can be prevented. |
openAutoFocus | Event | Event handler called when auto-focusing on open. Can be prevented. |
closeAutoFocus | Event | Event handler called when auto-focusing on close. Can be prevented. |
entryFocus | Event | Emitted when entry focus occurs. |
MenuGroup
Props
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
MenuGroupLabel
MenuItem
Props
| Prop | Type | Default | Description |
|---|---|---|---|
disabled | boolean | — | When `true`, prevents the user from interacting with the item. |
textValue | string | — | Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the
item. <br> Use this when the content is complex, or you have non-textual content inside. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
select | Event | Event handler called when the user selects an item (via mouse or keyboard). <br> Calling `event.preventDefault` in
this handler will prevent the menu from closing when selecting that item. |
MenuItemIndicator
Props
| Prop | Type | Default | Description |
|---|---|---|---|
forceMount | boolean | — | Used to force mounting when more control is needed.
Useful when controlling animation with Vue animation libraries. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
MenuOptionCompact<T>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
item | MenuOptionData<T extends DefinedValue = DefinedValue> | — | Current item data. |
itemProps | MenuItemProps | — | Properties forwarded to the item element. |
linkProps | LinkExtraProps | — | Properties forwarded to the link element. |
groupProps | MenuGroupProps | — | Properties forwarded to the group element. |
groupLabelProps | MenuGroupLabelProps | — | Properties forwarded to the group label element. |
subProps | MenuSubProps | — | Properties forwarded to the sub element. |
subTriggerProps | MenuSubTriggerProps | — | Properties forwarded to the sub trigger element. |
portalProps | PortalProps | — | Properties forwarded to the portal element. |
subContentProps | MenuSubContentProps | — | Properties forwarded to the sub content element. |
separatorProps | MenuSeparatorProps | — | Properties forwarded to the separator element. |
shortcutProps | MenuShortcutProps | — | Properties forwarded to the shortcut element. |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:open | boolean | Event handler called when the open state of the dialog changes. |
escapeKeyDown | KeyboardEvent | Event handler called when the escape key is down. Can be prevented. |
pointerDownOutside | PointerDownOutsideEvent | Event handler called when a `pointerdown` event happens outside of the `DismissableLayer`. Can be prevented. |
focusOutside | FocusOutsideEvent | Event handler called when the focus moves outside of the `DismissableLayer`. Can be prevented. |
interactOutside | PointerDownOutsideEvent | FocusOutsideEvent | Event handler called when an interaction happens outside the `DismissableLayer`. Specifically, when a `pointerdown`
event happens outside or focus moves outside of it. Can be prevented. |
openAutoFocus | Event | Event handler called when auto-focusing on open. Can be prevented. |
closeAutoFocus | Event | Event handler called when auto-focusing on close. Can be prevented. |
entryFocus | Event | Emitted when entry focus occurs. |
select | MenuOptionData<T>, event: Event | Emitted when select occurs. |
Slots
| Slot Name | Parameters | Description |
|---|---|---|
item | { item: MenuOptionData<T>; isTrigger?: boolean; } | Custom content for the item slot. |
item-leading | { item: MenuOptionData<T>; } | Custom content for the item leading slot. |
item-trailing | { item: MenuOptionData<T>; } | Custom content for the item trailing slot. |
item-trigger-icon | { item: MenuOptionData<T>; } | Custom content for the item trigger icon slot. |
item-link-icon | { item: MenuOptionData<T>; } | Custom content for the item link icon slot. |
MenuOptionCompactSelect<T>
Emits
| Emit Name | Parameters | Description |
|---|---|---|
select | MenuOptionData<T>, event: Event | Emitted when select occurs. |
MenuOptionsCompact<T>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | MenuOptionData<T>[] | — | Items rendered by the component. |
selectedValue | T | — | The selected value of the menu. |
itemProps | MenuItemProps | — | Properties forwarded to the item element. |
linkProps | LinkExtraProps | — | Properties forwarded to the link element. |
subProps | MenuSubProps | — | Properties forwarded to the sub element. |
groupProps | MenuGroupProps | — | Properties forwarded to the group element. |
groupLabelProps | MenuGroupLabelProps | — | Properties forwarded to the group label element. |
shortcutProps | MenuShortcutProps | — | Properties forwarded to the shortcut element. |
separatorProps | MenuSeparatorProps | — | Properties forwarded to the separator element. |
subTriggerProps | MenuSubTriggerProps | — | Properties forwarded to the sub trigger element. |
subContentProps | MenuSubContentProps | — | Properties forwarded to the sub content element. |
portalProps | PortalProps | — | Properties forwarded to the portal element. |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:open | boolean | Event handler called when the open state of the dialog changes. |
escapeKeyDown | KeyboardEvent | Event handler called when the escape key is down. Can be prevented. |
pointerDownOutside | PointerDownOutsideEvent | Event handler called when a `pointerdown` event happens outside of the `DismissableLayer`. Can be prevented. |
focusOutside | FocusOutsideEvent | Event handler called when the focus moves outside of the `DismissableLayer`. Can be prevented. |
interactOutside | PointerDownOutsideEvent | FocusOutsideEvent | Event handler called when an interaction happens outside the `DismissableLayer`. Specifically, when a `pointerdown`
event happens outside or focus moves outside of it. Can be prevented. |
openAutoFocus | Event | Event handler called when auto-focusing on open. Can be prevented. |
closeAutoFocus | Event | Event handler called when auto-focusing on close. Can be prevented. |
entryFocus | Event | Emitted when entry focus occurs. |
select | MenuOptionData<T>, event: Event | Emitted when select occurs. |
Slots
| Slot Name | Parameters | Description |
|---|---|---|
item | { item: MenuOptionData<T>; isTrigger?: boolean; } | Custom content for the item slot. |
item-leading | { item: MenuOptionData<T>; } | Custom content for the item leading slot. |
item-trailing | { item: MenuOptionData<T>; } | Custom content for the item trailing slot. |
item-trigger-icon | { item: MenuOptionData<T>; } | Custom content for the item trigger icon slot. |
item-link-icon | { item: MenuOptionData<T>; } | Custom content for the item link icon slot. |
MenuPortal
MenuRadioGroup<T = AcceptableBooleanValue>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | T | null | — | The controlled value of the radio item to check. Can be bound as `v-model`. |
defaultValue | T | — | The value of the radio item that should be checked when initially rendered. Use when you do not need to control the
state of the radio items. |
disabled | boolean | — | When `true`, prevents the user from interacting with radio items. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | Exclude<T, undefined> | null | Event handler called when the radio group value changes |
MenuRadioItem
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | number | boolean | — | The value given as data when submitted with a `name`. |
disabled | boolean | — | When `true`, prevents the user from interacting with the item. |
textValue | string | — | Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the
item. <br> Use this when the content is complex, or you have non-textual content inside. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
select | Event | Event handler called when the user selects an item (via mouse or keyboard). <br> Calling `event.preventDefault` in
this handler will prevent the menu from closing when selecting that item. |
MenuRadioOptionsCompact<T>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | MenuRadioOptionData<T>[] | — | Items rendered by the component. |
groupLabelProps | MenuGroupLabelProps | — | Properties forwarded to the group label element. |
radioItemProps | MenuRadioItemProps | — | Properties forwarded to the radio item element. |
indicatorProps | MenuItemIndicatorProps | — | Properties forwarded to the indicator element. |
shortcutProps | MenuShortcutProps | — | Properties forwarded to the shortcut element. |
separatorProps | MenuSeparatorProps | — | Properties forwarded to the separator element. |
modelValue | T | null | — | The controlled value of the radio item to check. Can be bound as `v-model`. |
defaultValue | T | — | The value of the radio item that should be checked when initially rendered. Use when you do not need to control the
state of the radio items. |
disabled | boolean | — | When `true`, prevents the user from interacting with radio items. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | Exclude<T, undefined> | null | Event handler called when the radio group value changes |
select | MenuRadioOptionData<T>, event: Event | Emitted when select occurs. |
Slots
| Slot Name | Parameters | Description |
|---|---|---|
item | MenuRadioOptionData<T> | Custom content for the item slot. |
item-leading | MenuRadioOptionData<T> | Custom content for the item leading slot. |
item-trailing | MenuRadioOptionData<T> | Custom content for the item trailing slot. |
item-indicator-icon | MenuRadioOptionData<T> | Custom content for the item indicator icon slot. |
MenuRadioOptionsCompactSelect<T>
Emits
| Emit Name | Parameters | Description |
|---|---|---|
select | MenuRadioOptionData<T>, event: Event | Emitted when select occurs. |
MenuRoot
Props
| Prop | Type | Default | Description |
|---|---|---|---|
dir | Direction | — | The reading direction of the combobox when applicable.
If omitted, inherits globally from `ConfigProvider` or assumes LTR (left-to-right) reading mode. |
open | boolean | undefined | The controlled open state of the dialog. Can be bound with `v-model:open`. |
defaultOpen | boolean | false | The open state of the dialog when it is initially rendered. Use when you do not need to control its open state. |
modal | boolean | true | The modality of the dialog. When set to `true`, interaction with outside elements will be disabled and only dialog
content will be visible to screen readers. |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:open | boolean | Event handler called when the open state of the dialog changes. |
MenuSeparator
MenuShortcut
Props
| Prop | Type | Default | Description |
|---|---|---|---|
symbolize | boolean | true | Whether to convert the command value to symbol representation. |
MenuSub
Props
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | undefined | The controlled open state of the dialog. Can be bound with `v-model:open`. |
defaultOpen | boolean | false | The open state of the dialog when it is initially rendered. Use when you do not need to control its open state. |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:open | boolean | Event handler called when the open state of the dialog changes. |
MenuSubContent
Props
| Prop | Type | Default | Description |
|---|---|---|---|
loop | boolean | false | Whether keyboard navigation should loop around |
placement | Placement | undefined | The placement of the floating element.
If used, it will override the `side` and `align` props. |
popupProps | MenuPopupProps | — | Properties forwarded to the popup element. |
sideOffset | number | 0 | The distance in pixels from the trigger. |
arrowPadding | number | 0 | The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it
from overflowing the corners. |
updatePositionStrategy | 'always' | 'optimized' | 'optimized' | Strategy to update the position of the floating element on every animation frame. |
sideFlip | boolean | true | Flip to the opposite side when colliding with boundary. |
alignOffset | number | 0 | An offset in pixels from the `start` or `end` alignment options. |
alignFlip | boolean | true | Flip alignment when colliding with boundary.
May only occur when `prioritizePosition` is true. |
avoidCollisions | boolean | true | When `true`, overrides the side and align preferences to prevent collisions with boundary edges. |
collisionBoundary | Element | (Element | null)[] | null | [ ] | The element used as the collision boundary. By default this is the viewport, though you can provide additional
element(s) to be included in this check. |
collisionPadding | Padding | 0 | The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for
all sides), or a partial padding object, for example: { top: 20, left: 20 }. |
hideShiftedArrow | boolean | true | When `true`, hides the arrow when it cannot be centered
to the reference element. |
sticky | 'partial' | 'always' | 'partial' | The sticky behavior on the align axis. `partial` will keep the content in the boundary as long as the trigger is at
least partially in the boundary whilst "always" will keep the content in the boundary regardless. |
hideWhenDetached | boolean | false | Whether to hide the content when the trigger becomes fully occluded. |
positionStrategy | 'fixed' | 'absolute' | 'fixed' | The type of CSS position property to use. |
disableUpdateOnLayoutShift | boolean | false | Whether to disable the update position for the content when the layout shifted. |
prioritizePosition | boolean | false | Force content to be position within the viewport. Might overlap the reference element, which may not be desired. |
reference | ReferenceElement | — | The custom element or virtual element that will be set as the reference to position the floating element. If
provided, it will replace the default anchor element. |
trapFocus | boolean | modal | Whether focus is trapped inside the popup while open (Tab cycles within the layer and body
scroll is locked for modal layers). |
disableHoverableContent | boolean | false | When `true`, hovering the popup closes instead of keeping it open (the grace area is disabled,
so leaving the trigger closes the layer immediately). |
onGracePointerExit | (() => void) | — | Callback invoked when the pointer finally leaves the grace area. Lets an upper layer (e.g.
Tooltip) run area-scoped close logic without registering its own second grace area. |
forceMount | boolean | — | Used to force mounting when more control is needed.
Useful when controlling animation with Vue animation libraries. |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
escapeKeyDown | KeyboardEvent | Event handler called when the escape key is down. Can be prevented. |
pointerDownOutside | PointerDownOutsideEvent | Event handler called when a `pointerdown` event happens outside of the `DismissableLayer`. Can be prevented. |
focusOutside | FocusOutsideEvent | Event handler called when the focus moves outside of the `DismissableLayer`. Can be prevented. |
interactOutside | PointerDownOutsideEvent | FocusOutsideEvent | Event handler called when an interaction happens outside the `DismissableLayer`. Specifically, when a `pointerdown`
event happens outside or focus moves outside of it. Can be prevented. |
openAutoFocus | Event | Event handler called when auto-focusing on open. Can be prevented. |
closeAutoFocus | Event | Event handler called when auto-focusing on close. Can be prevented. |
entryFocus | Event | Emitted when entry focus occurs. |
MenuSubTrigger
Props
| Prop | Type | Default | Description |
|---|---|---|---|
disabled | boolean | — | When `true`, prevents the user from interacting with the item. |
textValue | string | — | Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the
item. <br> Use this when the content is complex, or you have non-textual content inside. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
MenuTrigger
Props
| Prop | Type | Default | Description |
|---|---|---|---|
type | ButtonType | 'button' | The type of the button element. Can be one of 'button', 'submit', or 'reset'. |
disabled | boolean | — | Whether the component is disabled. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Notes
Architecture and benchmark comparison
| Concern | VeanUI | Radix UI Menu | Ant Design Menu / Dropdown | Element Plus Dropdown |
|---|---|---|---|---|
| Aria / styled split | ✅ @vean/aria/menu + scv() | ✅ Aria | ❌ single package | ❌ single package |
| Data-driven compact API | ✅ plain/checkbox/radio | ❌ composition | ✅ config-driven (items) | ✅ config-driven |
| roving focus + typeahead | ✅ full model (Home/End/PageUp/PageDown) | ✅ | partial | partial |
| Submenu arrow keys | ✅ ArrowRight/Left (dir-aware) | ✅ | partial | partial |
| Checkbox / radio items | ✅ menuitemcheckbox / menuitemradio | ✅ | ✅ | partial |
'mixed' indeterminate | ✅ CheckedState | ✅ | ✅ | — |
| Floating positioning | ✅ floating-ui (arrow/size/flip/…) | ✅ | ✅ | ✅ |
| Separator / shortcut | ✅ separator / shortcut | component combo | ✅ (divider / command) | partial |
| Grouping | ✅ isGroupLabel + MenuGroupLabel | ✅ MenuGroup | ✅ (type:‘group’) | partial |
— = not supported or uses a different interaction model.
Runtime considerations
itemsdata shape —MenuOptionDataincludeslabel/value/icon/shortcut/separator/isGroupLabel/children;childrenrecursively renders submenus. Checkbox/radio shapes each have their own type.- Controlled / uncontrolled — checkbox and radio groups support
modelValue/defaultValue(useControllableState); a radio group’smodelValuecan benull(no selection). - Keyboard activation — roving focus is maintained by
useRovingFocusGroup; typeahead jumps by character (skipping disabled);Esccloses viauseDismissableLayerand returns focus to the trigger. - Disabled fallback — per-item
disabledwins overitemProps.disabled; disabled items arearia-disabled+tabindex="-1"but stay registered so typeahead can skip them. - Floating lifecycle — dismissable layer + Presence (
forceMount); body scroll lock and focus scope are enabled when Root’s modal mode is on. - Link items — items with
href/torender as links (reusing the Link primitive);itemProps/linkPropsforward attributes. selectevent payload —select(item, event)carries the selected item and the native event; the menu close can be controlled viaevent.defaultPrevented.
FAQ
How do I create an item with a submenu?
Provide a children array on the MenuOptionData to render a submenu recursively; submenus support further nesting.
How do checkbox and radio items bind values?
Checkbox uses v-model bound to an array (CheckedState[], supports 'mixed'); radio uses v-model bound to an AcceptableBooleanValue (can be null for no selection).
How do I add separators and shortcuts?
Set separator: true on an item to render a divider after it; set shortcut (KbdValue or array) to render a keyboard hint at the item’s end.
How does keyboard navigation work?
Arrow keys move focus (dir-aware); typing letters triggers typeahead; Home/End jump to first/last; Enter/Space select; Esc closes and returns focus; Tab loops inside the menu; submenus open/close via ArrowRight/ArrowLeft.
Can I build a fully custom menu?
Yes — compose MenuRoot / MenuContent / MenuItem / MenuCheckboxItem / MenuRadioItem / MenuSub / MenuGroup primitives from @vean/aria/menu and inject styles via provideMenuUi (or SMenuOptions’s ui prop).