Menu
Navigate hierarchical commands, open submenus, and invoke an action.
Usage
Command list
Run common project commands from one flat command list.
Run common project commands from one flat command list.
<!-- Menu / Commands -->
<script setup lang="ts">
import { MenuRoot, MenuItem, MenuSeparator } from '@sectile/vue/menu'
import { ref } from 'vue'
const lastAction = ref('')
const items = [
{ id: 'new-project', parentID: null },
{ id: 'open-project', parentID: null },
{ id: 'save-project', parentID: null },
]
</script>
<template>
<MenuRoot :items="items" @invoke="lastAction = $event">
<MenuItem value="new-project">New project <kbd>⌘N</kbd></MenuItem>
<MenuItem value="open-project">Open project <kbd>⌘O</kbd></MenuItem>
<MenuSeparator />
<MenuItem value="save-project">Save project <kbd>⌘S</kbd></MenuItem>
</MenuRoot>
<p v-if="lastAction" role="status">{{ lastAction }} invoked</p>
</template>Disabled
Remove the control from keyboard and pointer interaction.
Remove the control from keyboard and pointer interaction.
<!-- Menu / Disabled -->
<script setup lang="ts">
import { MenuRoot, MenuItem } from '@sectile/vue/menu'
const items = [
{ id: 'preview', parentID: null },
{ id: 'deploy', parentID: null },
{ id: 'cancel', parentID: null },
]
</script>
<template>
<MenuRoot :items="items" :disabled-items="['deploy']">
<MenuItem value="preview">Preview release</MenuItem>
<MenuItem value="deploy">Deploy (unavailable)</MenuItem>
<MenuItem value="cancel">Cancel release</MenuItem>
</MenuRoot>
</template>Nested submenu
Choose an export format from a submenu owned by the Export command.
Choose an export format from a submenu owned by the Export command.
<!-- Menu / Nested -->
<script setup lang="ts">
import { MenuRoot, MenuItem, MenuSubContent, MenuSeparator } from '@sectile/vue/menu'
import { ref } from 'vue'
const lastAction = ref('')
const items = [
{ id: 'export', parentID: null },
{ id: 'pdf', parentID: 'export' },
{ id: 'markdown', parentID: 'export' },
{ id: 'csv', parentID: 'export' },
{ id: 'share', parentID: null },
]
</script>
<template>
<MenuRoot :items="items" @invoke="lastAction = $event">
<MenuItem value="export">Export as ›</MenuItem>
<MenuSubContent for="export">
<MenuItem value="pdf">PDF document</MenuItem>
<MenuItem value="markdown">Markdown</MenuItem>
<MenuItem value="csv">CSV data</MenuItem>
</MenuSubContent>
<MenuSeparator />
<MenuItem value="share">Share link <kbd>⌘L</kbd></MenuItem>
</MenuRoot>
<p v-if="lastAction" role="status">{{ lastAction }} invoked</p>
</template>Floating positioning
This component uses the shared positioning engine. Use the live positioning example to change side, align, offsets, collision boundaries, strategy, and tracking while inspecting the resolved placement.
API
Vue package: @sectile/vue/menu
MenuRootMenubarRootNavigationMenuRootMenuButtonRootMenuButtonTriggerMenuButtonContentMenuItemMenuSubContentMenuSeparator
Props
MenuRootProps
as- Type
PrimitiveAsDefaultundefinedElement or component rendered for this part.
asChild- Type
booleanDefaultundefinedWhether to merge this part into its single child instead of rendering a wrapper.
defaultHighlightedValue- Type
string | nullDefaultundefinedInitially highlighted value for uncontrolled state.
disabled- Type
booleanDefaultundefinedWhether interaction is unavailable.
disabledItems- Type
readonly string[]DefaultundefinedItem values excluded from focus and selection.
items- Type
readonly MenuItemDefinition<string>[]DefaultRequiredOrdered item values managed by the component.
label- Type
stringDefaultundefinedAccessible name announced for the control.
policies- Type
MenuPolicies<string>DefaultundefinedBehavior policies that customize validation, movement, or selection.
textValue- Type
(id: string) => stringDefaultundefinedReturns searchable or presentational text for an item value.
MenuButtonRootProps
align- Type
PositionAlignDefaultundefinedAlignment of positioned content relative to its anchor.
as- Type
PrimitiveAsDefaultundefinedElement or component rendered for this part.
asChild- Type
booleanDefaultundefinedWhether to merge this part into its single child instead of rendering a wrapper.
avoidCollisions- Type
booleanDefaultundefinedWhether positioned content may flip or shift to remain visible.
collisionBoundary- Type
PositionBoundaryDefaultundefinedBoundary used to keep positioned content visible.
collisionPadding- Type
PositionPaddingDefaultundefinedSpace kept between positioned content and its collision boundary.
defaultHighlightedValue- Type
string | nullDefaultundefinedInitially highlighted value for uncontrolled state.
defaultOpen- Type
booleanDefaultundefinedInitial uncontrolled open state.
disabled- Type
booleanDefaultundefinedWhether interaction is unavailable.
disabledItems- Type
readonly string[]DefaultundefinedItem values excluded from focus and selection.
hideWhenDetached- Type
booleanDefaultundefinedWhether positioned content hides when its anchor leaves the layout.
items- Type
readonly MenuItemDefinition<string>[]DefaultRequiredOrdered item values managed by the component.
label- Type
stringDefaultundefinedAccessible name announced for the control.
open- Type
booleanDefaultundefinedWhether the associated popup or disclosure is open.
policies- Type
MenuPolicies<string>DefaultundefinedBehavior policies that customize validation, movement, or selection.
position- Type
booleanDefaultundefinedWhether the popup is positioned relative to its trigger.
side- Type
PositionSideDefaultundefinedPreferred side of the anchor for positioned content.
sideOffset- Type
numberDefaultundefinedDistance between positioned content and its anchor.
strategy- Type
PositionStrategyDefaultundefinedCSS positioning strategy used for anchored content.
textValue- Type
(id: string) => stringDefaultundefinedReturns searchable or presentational text for an item value.
tracking- Type
PositionTrackingDefaultundefinedUpdate strategy used while anchored content is open.
MenuItemProps
as- Type
PrimitiveAsDefaultundefinedElement or component rendered for this part.
asChild- Type
booleanDefaultundefinedWhether to merge this part into its single child instead of rendering a wrapper.
disabled- Type
booleanDefaultfalseWhether interaction is unavailable.
value- Type
stringDefaultRequiredCurrent value exposed by this contract.
MenuSubContentProps
as- Type
PrimitiveAsDefaultundefinedElement or component rendered for this part.
asChild- Type
booleanDefaultundefinedWhether to merge this part into its single child instead of rendering a wrapper.
for- Type
stringDefaultRequiredValue or ID of the related part targeted by this component.
MenuPartProps
as- Type
PrimitiveAsDefaultVaries by partElement or component rendered for this part.
asChild- Type
booleanDefaultfalseWhether to merge this part into its single child instead of rendering a wrapper.
Slots
MenuRootSlotProps
disabled- Type
booleanWhether interaction is unavailable.
highlightedValue- Type
string | nullValue currently highlighted for interaction.
open- Type
booleanWhether the associated popup or disclosure is open.
openPath- Type
readonly string[]Ordered values in the open menu path.
MenuItemSlotProps
disabled- Type
booleanWhether interaction is unavailable.
highlighted- Type
booleanWhether this item is highlighted for interaction.
open- Type
booleanWhether the associated popup or disclosure is open.
value- Type
stringCurrent value exposed by this contract.
Events
MenuRoot
invoke- Payload
stringEmitted when the current action is invoked.
update:open- Payload
booleanEmitted when the component requests a new open state.
MenubarRoot
invoke- Payload
stringEmitted when the current action is invoked.
update:open- Payload
booleanEmitted when the component requests a new open state.
NavigationMenuRoot
invoke- Payload
stringEmitted when the current action is invoked.
update:open- Payload
booleanEmitted when the component requests a new open state.
MenuButtonRoot
invoke- Payload
stringEmitted when the current action is invoked.
update:open- Payload
booleanEmitted when the component requests a new open state.
Other types
MenuTextValueResolver
type MenuTextValueResolver = NonNullable<MenuRootProps['textValue']>MenuOpenChangeHandler
type MenuOpenChangeHandler = NonNullable<InstanceType<typeof MenuRoot>['$props']['onUpdate:open']>MenuInvokeHandler
type MenuInvokeHandler = NonNullable<InstanceType<typeof MenuRoot>['$props']['onInvoke']>MenubarOpenChangeHandler
type MenubarOpenChangeHandler = NonNullable<InstanceType<typeof MenubarRoot>['$props']['onUpdate:open']>MenubarInvokeHandler
type MenubarInvokeHandler = NonNullable<InstanceType<typeof MenubarRoot>['$props']['onInvoke']>NavigationMenuOpenChangeHandler
type NavigationMenuOpenChangeHandler = NonNullable<InstanceType<typeof NavigationMenuRoot>['$props']['onUpdate:open']>NavigationMenuInvokeHandler
type NavigationMenuInvokeHandler = NonNullable<InstanceType<typeof NavigationMenuRoot>['$props']['onInvoke']>MenuButtonOpenChangeHandler
type MenuButtonOpenChangeHandler = NonNullable<InstanceType<typeof MenuButtonRoot>['$props']['onUpdate:open']>MenuButtonInvokeHandler
type MenuButtonInvokeHandler = NonNullable<InstanceType<typeof MenuButtonRoot>['$props']['onInvoke']>Parts
Shared scope: [data-scope="menu"]. Combine it with a part selector to keep styles local to this component.
| Part | Selector | Role | Extra attributes |
|---|---|---|---|
root | [data-part="root"] | Defines the component boundary and owns its composed parts. | — |
item | [data-part="item"] | Menu item at any hierarchy depth; use data-level to distinguish top-level and nested items | data-level="<depth>" |
sub-content | [data-part="sub-content"] | Popup content owned by a parent menu item | data-level="<depth>" |
separator | [data-part="separator"] | Separates related groups without becoming an action. | — |
Keyboard interaction
| Key | Behavior |
|---|---|
| Arrow Up / Arrow Down | Move between items at the current menu level. |
| Arrow Right / Arrow Left | Open a submenu or return to its parent. |
| Home / End | Move to the first or last item at the current level. |
| Enter / Space | Open a submenu or invoke the current item. |
| Escape | Close the current menu level. |
Accessibility
Menu items, separators, and nested menu state use hierarchical menu semantics and roving focus.
See the corresponding WAI-ARIA pattern for the host accessibility contract.
