Back to catalog
Component detail entry
Navigation
@vean/ui
SMenu

Menu

Menu belongs to the Navigation category. Start with demos and usage, then use the API tables to finish integration and styling decisions.

Use the quick jump panel to reach overview, usage, demos, and API first, then continue through the full page.

Quick jump

Related components

If you are composing interactions in the same family, these components usually pair well together.

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 / SMenuRadioOptions recursively render items from an items array; the Aria MenuOptionsCompact owns 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/size middleware) with arrow, placement, sideOffset, and CSS variable forwarding.
  • Three data shapes — plain MenuOptionData (icon/shortcut/separator/link/submenu), checkbox MenuCheckboxOptionData (CheckedState including 'mixed'), and radio MenuRadioOptionData (AcceptableBooleanValue), each with its own group.
  • Grouping & separators — isGroupLabel renders a MenuGroupLabel heading, separator renders a divider, and shortcut renders 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 disabled with itemProps.disabled fallback (explicit value wins), aria-disabled + tabindex="-1".
  • Hidden items — per-item hidden drops 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 / MenuGroup exported 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 by SMenuOptions (can be used standalone).
  • SMenuCheckboxOptions — a group of checkbox items (v-model array / CheckedState).
  • SMenuRadioOptions — a group of radio items (v-model bound to AcceptableBooleanValue).

Usage

Demos

Basic

API

Aria Layer

27

ContextMenuPopup

MenuAnchor

MenuArrow

MenuCheckboxGroup<T extends DefinedValue = DefinedValue>

5 Props1 Emits
Props
PropTypeDefaultDescription
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 NameParametersDescription
update:modelValue
T[]
Event handler called when the value of the checkbox group changes.

MenuCheckboxItem

6 Props2 Emits
Props
PropTypeDefaultDescription
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 NameParametersDescription
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>

11 Props2 Emits4 Slots
Props
PropTypeDefaultDescription
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 NameParametersDescription
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 NameParametersDescription
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>

1 Emits
Emits
Emit NameParametersDescription
select
MenuCheckboxOptionData<T>, event: Event
Emitted when select occurs.

MenuContent

25 Props7 Emits
Props
PropTypeDefaultDescription
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 NameParametersDescription
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

2 Props
Props
PropTypeDefaultDescription
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

4 Props1 Emits
Props
PropTypeDefaultDescription
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 NameParametersDescription
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

3 Props
Props
PropTypeDefaultDescription
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>

11 Props9 Emits5 Slots
Props
PropTypeDefaultDescription
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 NameParametersDescription
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 NameParametersDescription
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>

1 Emits
Emits
Emit NameParametersDescription
select
MenuOptionData<T>, event: Event
Emitted when select occurs.

MenuOptionsCompact<T>

12 Props9 Emits5 Slots
Props
PropTypeDefaultDescription
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 NameParametersDescription
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 NameParametersDescription
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>

5 Props1 Emits
Props
PropTypeDefaultDescription
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 NameParametersDescription
update:modelValue
Exclude<T, undefined> | null
Event handler called when the radio group value changes

MenuRadioItem

5 Props1 Emits
Props
PropTypeDefaultDescription
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 NameParametersDescription
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>

11 Props2 Emits4 Slots
Props
PropTypeDefaultDescription
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 NameParametersDescription
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 NameParametersDescription
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>

1 Emits
Emits
Emit NameParametersDescription
select
MenuRadioOptionData<T>, event: Event
Emitted when select occurs.

MenuRoot

4 Props1 Emits
Props
PropTypeDefaultDescription
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 NameParametersDescription
update:open
boolean
Event handler called when the open state of the dialog changes.

MenuSeparator

MenuShortcut

1 Props
Props
PropTypeDefaultDescription
symbolize
boolean
true
Whether to convert the command value to symbol representation.

MenuSub

2 Props1 Emits
Props
PropTypeDefaultDescription
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 NameParametersDescription
update:open
boolean
Event handler called when the open state of the dialog changes.

MenuSubContent

23 Props7 Emits
Props
PropTypeDefaultDescription
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 NameParametersDescription
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

4 Props
Props
PropTypeDefaultDescription
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

4 Props
Props
PropTypeDefaultDescription
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

ConcernVeanUIRadix UI MenuAnt Design Menu / DropdownElement 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)✅partialpartial
Submenu arrow keys✅ ArrowRight/Left (dir-aware)✅partialpartial
Checkbox / radio items✅ menuitemcheckbox / menuitemradio✅✅partial
'mixed' indeterminate✅ CheckedState✅✅—
Floating positioning✅ floating-ui (arrow/size/flip/…)✅✅✅
Separator / shortcut✅ separator / shortcutcomponent combo✅ (divider / command)partial
Grouping✅ isGroupLabel + MenuGroupLabel✅ MenuGroup✅ (type:‘group’)partial

— = not supported or uses a different interaction model.

Runtime considerations

  1. items data shape — MenuOptionData includes label/value/icon/shortcut/separator/isGroupLabel/children; children recursively renders submenus. Checkbox/radio shapes each have their own type.
  2. Controlled / uncontrolled — checkbox and radio groups support modelValue / defaultValue (useControllableState); a radio group’s modelValue can be null (no selection).
  3. Keyboard activation — roving focus is maintained by useRovingFocusGroup; typeahead jumps by character (skipping disabled); Esc closes via useDismissableLayer and returns focus to the trigger.
  4. Disabled fallback — per-item disabled wins over itemProps.disabled; disabled items are aria-disabled + tabindex="-1" but stay registered so typeahead can skip them.
  5. Floating lifecycle — dismissable layer + Presence (forceMount); body scroll lock and focus scope are enabled when Root’s modal mode is on.
  6. Link items — items with href/to render as links (reusing the Link primitive); itemProps / linkProps forward attributes.
  7. select event payload — select(item, event) carries the selected item and the native event; the menu close can be controlled via event.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).

Changelog

Version history is grouped by release so you can quickly see what changed for this component across published versions.

v0.31.0

2026-08-31

Compare release

Style

optimize menu space

Scope: menuAuthors: soybeanjsView commit5c0a5

v0.30.0

2026-08-20

Compare release

Optimization

add default prioritizePosition prop

Scope: menuAuthors: soybeanjsView commit0b47e

Optimization

add default prioritizePosition prop

Scope: menuAuthors: soybeanjsView commit45fed

Optimization

add default prioritizePosition prop

Scope: menuAuthors: soybeanjsView commit0b47e

Optimization

add default prioritizePosition prop

Scope: menuAuthors: soybeanjsView commit45fed

v0.15.0

2026-04-26

Compare release

Feature

add MenuSubAttributeContext and integrate into menu components

Scope: menuAuthors: soybeanjsView commit7bc9f

Fix

correct focus handling in PopperPositioner and RovingFocusGroup

Scope: menuAuthors: soybeanjsView commit68b9d

Refactor

Implement Menu Compact components

Scope: menuAuthors: soybeanjsView commita1e6d

Chore

add unit tests for SMenuOptions keyboard navigation

Scope: menuAuthors: soybeanjsView commita4532

Style

change cursor style from default to pointer for menu items

Scope: menuAuthors: soybeanjsView commitc47ff

Feature

add MenuSubAttributeContext and integrate into menu components

Scope: menuAuthors: soybeanjsView commit7bc9f

Fix

correct focus handling in PopperPositioner and RovingFocusGroup

Scope: menuAuthors: soybeanjsView commit68b9d

Refactor

Implement Menu Compact components

Scope: menuAuthors: soybeanjsView commita1e6d

Chore

add unit tests for SMenuOptions keyboard navigation

Scope: menuAuthors: soybeanjsView commita4532

Style

change cursor style from default to pointer for menu items

Scope: menuAuthors: soybeanjsView commitc47ff

v0.14.0

2026-04-03

Compare release

Refactor

enhance menu item radio and checkbox components

Scope: menuAuthors: soybeanjsView commit233ff

v0.3.0

2026-01-29

Compare release

Feature

support active state

Scope: menuAuthors: soybeanjsView commit32476

v0.1.11

2026-01-28

Compare release

Fix

add focus-visible outline to popup for better accessibility

Scope: menuAuthors: soybeanjsView commitf5509

v0.0.20

2026-01-21

Compare release

Feature

support indicator position

Scope: menuAuthors: soybeanjsView commitf7da3

v0.0.8

2026-01-01

Compare release

Optimization

enhance type definitions

Scope: menuAuthors: soybeanjsView commite2fb8

Refactor

restructure menu components by introducing popup and positioner elements, updating context management, and enhancing type definitions for improved clarity and functionality

Scope: menuAuthors: soybeanjsView commitf4143

v0.0.2

2025-11-18

Compare release

Feature

implement menu component structure with context management, navigation, and accessibility features

Scope: menuAuthors: soybeanjsView commite27d7

Feature

add MenuSubTrigger component and update MenuRoot props for improved functionality

Scope: menuAuthors: soybeanjsView commitc3b85

Feature

add menu component names

Scope: menuAuthors: soybeanjsView commit58293

Feature

replace MenuLabel with MenuGroupLabel and add theme context support for menu components

Scope: menuAuthors: soybeanjsView commit02a5b

Fix

update dismissable layer to use contentElement and improve focus handling with new utility functions

Scope: menuAuthors: soybeanjsView commit9cbc7

Fix

update filter logic to include only common slots

Scope: menuAuthors: soybeanjsView commitb4810

Fix

bind separatorProps to MenuSeparator for improved functionality

Scope: menuAuthors: soybeanjsView commitda975

Fix

adjust content min-width in menu variants for better layout

Scope: menuAuthors: soybeanjsView commit50e8b

Refactor

remove unused useCollection composable and integrate useHideOthers for better focus management

Scope: menuAuthors: soybeanjsView commit6a02b

Refactor

streamline context management and enhance element handling across menu components

Scope: menuAuthors: soybeanjsView commit976cf

Refactor

enhance element management by integrating PopperContentWrapper and callback handlers for improved structure and focus handling

Scope: menuAuthors: soybeanjsView commitd1596

Refactor

update MenuContent to use MenuContentPrivateProps and enhance element forwarding with elRef

Scope: menuAuthors: soybeanjsView commit2e946

Refactor

move SELECTION_KEYS import to constants for better organization and consistency across components

Scope: menuAuthors: soybeanjsView commita4d33

Feature

implement menu component structure with context management, navigation, and accessibility features

Scope: menuAuthors: soybeanjsView commite27d7

Feature

add MenuSubTrigger component and update MenuRoot props for improved functionality

Scope: menuAuthors: soybeanjsView commitc3b85

Feature

add menu component names

Scope: menuAuthors: soybeanjsView commit58293

Feature

replace MenuLabel with MenuGroupLabel and add theme context support for menu components

Scope: menuAuthors: soybeanjsView commit02a5b

Fix

update dismissable layer to use contentElement and improve focus handling with new utility functions

Scope: menuAuthors: soybeanjsView commit9cbc7

Fix

update filter logic to include only common slots

Scope: menuAuthors: soybeanjsView commitb4810

Fix

bind separatorProps to MenuSeparator for improved functionality

Scope: menuAuthors: soybeanjsView commitda975

Fix

adjust content min-width in menu variants for better layout

Scope: menuAuthors: soybeanjsView commit50e8b

Refactor

remove unused useCollection composable and integrate useHideOthers for better focus management

Scope: menuAuthors: soybeanjsView commit6a02b

Refactor

streamline context management and enhance element handling across menu components

Scope: menuAuthors: soybeanjsView commit976cf

Refactor

enhance element management by integrating PopperContentWrapper and callback handlers for improved structure and focus handling

Scope: menuAuthors: soybeanjsView commitd1596

Refactor

update MenuContent to use MenuContentPrivateProps and enhance element forwarding with elRef

Scope: menuAuthors: soybeanjsView commit2e946

Refactor

move SELECTION_KEYS import to constants for better organization and consistency across components

Scope: menuAuthors: soybeanjsView commita4d33