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

Menubar

Menubar 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.

Menubar

Overview

Menubar builds a persistent horizontal menu bar for application chrome: a row of triggers with roving focus that open dropdown menus on click or hover, with arbitrarily nested submenus and full keyboard navigation.

SMenubar is a data-driven aggregation component: pass an items array and it renders the full role="menubar" structure, triggers, dropdown content, and nested submenus. A top-level item can be either a trigger that opens a dropdown or a link that navigates (set href / to). Logic and accessibility semantics live in the Aria MenubarCompact; styles are injected through a scv() recipe.

SMenubar delegates all structural composition to the Aria MenubarCompact. For unstyled data-driven usage, import from @vean/aria/menubar; the dropdown layer reuses MenuOptionsCompact from @vean/aria/menu.

Features

  • Data-driven composition — pass items (MenuOptionData) to render the menubar; top-level items declare dropdowns via children, and child items support label / icon / shortcut / disabled / separator / href / to with unlimited nesting.
  • Horizontal roving focus — the root keeps a single tab stop; ArrowLeft / ArrowRight move focus between triggers and loop wraps around at the ends; disabled triggers drop out of the focus order.
  • Full keyboard navigation — Enter / Space toggle the menu and ArrowDown opens it; arrow keys roam menu items, ArrowRight / ArrowLeft switch between neighboring top-level menus; Escape closes and restores focus.
  • Hover / pointer switching — with a menu open, hovering another trigger switches the open menu; hovering a link trigger dismisses the menu and focuses the link.
  • Click / hover trigger modes — trigger supports click (default) and hover: click opens on click while hovering an open menubar still switches menus; hover opens on hover (tune with delayDuration / skipDelayDuration) and includes a pointer grace area so the pointer can move between the menubar and the content without accidental closes.
  • Overflow collapsing — with collapsible, when the menubar content is wider than its container, trailing top-level items merge into a trailing “more” menu so the content always fits; customize via moreLabel / moreIcon / moreProps / the more-trigger slot.
  • Link top-level items — items with href / to render as links (no dropdown), matching the nav-menu pattern; link semantics for target / external / disabled are preserved.
  • Nested submenus — child items render arbitrarily deep submenus via MenuSub, with arrow-key entry/exit and a pointer-grace debounce (100ms open delay).
  • Controlled / uncontrolled — with modelValue, the open menu follows the prop and emits update:modelValue; otherwise defaultValue seeds the initial state.
  • Per-item and whole-bar disabling — item.disabled makes a single top-level trigger fully inert (aria-disabled + out of tab order + blocked interaction); the compact-level disabled prop disables every trigger at once, including link triggers.
  • Hidden items — item.hidden drops a top-level trigger and its dropdown; hidden items are filtered before the overflow math, so collapsible only counts visible triggers. Hidden child items are dropped from their dropdown.
  • Bidirectional direction — dir supports LTR / RTL; arrow keys and submenu slide direction follow logical direction; portalProps controls whether content teleports to body.
  • Six sizes — size (xs…2xl) variants cover root and trigger spacing, padding, and font size.
  • Menu slot passthrough — item-leading / item-trailing / trigger / item-link-icon slots forward to the menu layer for per-item customization; the ui prop overrides root and trigger slots.
  • Aria composition — MenubarRoot / MenubarMenu / MenubarTrigger / MenubarContent / MenubarSubTrigger / MenubarSubContent and Compact are all exported from @vean/aria/menubar; menu primitives are reused from @vean/aria/menu.

Usage

Demos

Basic

Controlled

Active menu:

TriggerMode

Triggerclickhover

Overflow

Collapsible

API

Aria Layer

21

Menubar<T>

36 Props10 Emits7 Slots
Props
PropTypeDefaultDescription
class
ClassValue
—
class of menubar root
size
ThemeSize
—
Visual size of the component.
ui
Partial<MenubarUi>
—
Per-slot class overrides for the component.
indicatorPosition
AlignSide
—
Indicator position.
disabled
boolean
—
Whether the component is disabled.
placement
Placement
—
Placement.
showArrow
boolean
—
Whether to show an arrow.
triggerProps
MenubarTriggerProps
—
Properties forwarded to the trigger element.
collapsible
boolean
—
When `true`, if the menubar content is wider than its container, the trailing items collapse into a trailing "more" menu so the content always fits inside the container.
moreLabel
string
undefined
Label of the trailing "more" trigger when `collapsible`.
moreIcon
IconValue
—
Icon of the trailing "more" trigger when `collapsible`.
moreProps
MenubarTriggerProps
—
Properties forwarded to the trailing "more" trigger.
portalProps
MenuPortalProps
—
Properties forwarded to the portal element.
contentProps
MenubarContentProps
—
Properties forwarded to the content element.
popupProps
MenuPopupProps
—
Properties forwarded to the popup element.
arrowProps
MenuArrowProps
—
Properties forwarded to the arrow element.
modelValue
T
—
The controlled value of the menu to open. Can be used as `v-model`.
defaultValue
T
—
The value of the menu that should be open when initially rendered.
dir
Direction
—
The reading direction of the menubar when applicable.
loop
boolean
—
When `true`, keyboard navigation loops from last trigger to first and vice versa.
trigger
MenubarTriggerType
'click'
The trigger type of the menubar. - `click`: The menu will be opened when the trigger is clicked (hovering an open menubar still switches between menus). - `hover`: The menu will be opened when the trigger is hovered.
delayDuration
number
150
The duration from when the pointer enters the trigger until the menu gets opened in hover mode.
skipDelayDuration
number
300
How much time a user has to enter another trigger without incurring a delay again.
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`
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.
Emits
Emit NameParametersDescription
update:modelValue
T
Emitted when the model value 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.
update:open
boolean
Event handler called when the open state of the dialog changes.
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.
trigger
((data: { item: MenuOptionData<T>; }) => any)
Custom content for the trigger slot. Optional: `MenubarCompact` renders full default trigger content (icon, label, link icon, trailing slot) when the consumer does not provide it.
more-trigger
—
Custom content for the trailing "more" trigger when `collapsible`.

MenubarArrow

MenubarCheckboxGroup

MenubarCheckboxItem

MenubarCompact<T>

32 Props10 Emits7 Slots
Props
PropTypeDefaultDescription
disabled
boolean
—
Whether the component is disabled.
placement
Placement
—
Placement.
showArrow
boolean
—
Whether to show an arrow.
triggerProps
MenubarTriggerProps
—
Properties forwarded to the trigger element.
collapsible
boolean
—
When `true`, if the menubar content is wider than its container, the trailing items collapse into a trailing "more" menu so the content always fits inside the container.
moreLabel
string
undefined
Label of the trailing "more" trigger when `collapsible`.
moreIcon
IconValue
—
Icon of the trailing "more" trigger when `collapsible`.
moreProps
MenubarTriggerProps
—
Properties forwarded to the trailing "more" trigger.
portalProps
MenuPortalProps
—
Properties forwarded to the portal element.
contentProps
MenubarContentProps
—
Properties forwarded to the content element.
popupProps
MenuPopupProps
—
Properties forwarded to the popup element.
arrowProps
MenuArrowProps
—
Properties forwarded to the arrow element.
modelValue
T
—
The controlled value of the menu to open. Can be used as `v-model`.
defaultValue
T
—
The value of the menu that should be open when initially rendered.
dir
Direction
—
The reading direction of the menubar when applicable.
loop
boolean
—
When `true`, keyboard navigation loops from last trigger to first and vice versa.
trigger
MenubarTriggerType
'click'
The trigger type of the menubar. - `click`: The menu will be opened when the trigger is clicked (hovering an open menubar still switches between menus). - `hover`: The menu will be opened when the trigger is hovered.
delayDuration
number
150
The duration from when the pointer enters the trigger until the menu gets opened in hover mode.
skipDelayDuration
number
300
How much time a user has to enter another trigger without incurring a delay again.
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`
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.
Emits
Emit NameParametersDescription
update:modelValue
T
Emitted when the model value 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.
update:open
boolean
Event handler called when the open state of the dialog changes.
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.
trigger
((data: { item: MenuOptionData<T>; }) => any)
Custom content for the trigger slot. Optional: `MenubarCompact` renders full default trigger content (icon, label, link icon, trailing slot) when the consumer does not provide it.
more-trigger
—
Custom content for the trailing "more" trigger when `collapsible`.

MenubarContent

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.

MenubarGroup

MenubarGroupLabel

MenubarItem

MenubarItemIndicator

MenubarMenu

1 Props
Props
PropTypeDefaultDescription
value
DefinedValue
—
A unique value that associates the trigger with the active root value when controlled.

MenubarMenus<T>

12 Props
Props
PropTypeDefaultDescription
items
MenuOptionData<T>[]
—
Top-level items rendered as visible triggers.
moreItems
MenuOptionData<T>[]
—
Items collapsed into the trailing "more" menu.
rootProps
{ [x: string]: unknown; }
—
Props forwarded to the menubar root.
listeners
{ [x: string]: unknown; }
—
Listeners forwarded to the menubar root.
optionsProps
{ [x: string]: unknown; }
—
Props forwarded to the menu options of each open menu.
linkProps
LinkExtraProps
—
Props forwarded to link triggers.
contentProps
MenubarContentProps
—
Props forwarded to the content of each menu.
portalProps
MenuPortalProps
—
Props forwarded to the portal of each menu.
getTriggerProps
(item: MenuOptionData<T>) => MenubarTriggerProps
—
Resolve the effective props of a top-level trigger item.
moreTriggerProps
{ [x: string]: unknown; }
—
Props forwarded to the trailing "more" trigger.
moreLabel
string
—
Label of the trailing "more" trigger.
moreIcon
IconValue
—
Icon of the trailing "more" trigger.

MenubarPortal

MenubarRadioGroup

MenubarRadioItem

MenubarRoot<T>

9 Props1 Emits
Props
PropTypeDefaultDescription
modelValue
T
—
The controlled value of the menu to open. Can be used as `v-model`.
defaultValue
T
—
The value of the menu that should be open when initially rendered.
dir
Direction
—
The reading direction of the menubar when applicable.
loop
boolean
—
When `true`, keyboard navigation loops from last trigger to first and vice versa.
trigger
MenubarTriggerType
'click'
The trigger type of the menubar. - `click`: The menu will be opened when the trigger is clicked (hovering an open menubar still switches between menus). - `hover`: The menu will be opened when the trigger is hovered.
delayDuration
number
150
The duration from when the pointer enters the trigger until the menu gets opened in hover mode.
skipDelayDuration
number
300
How much time a user has to enter another trigger without incurring a delay again.
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
Emitted when the model value changes.

MenubarSeparator

MenubarSub

MenubarSubContent

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.

MenubarSubTrigger

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`

MenubarTrigger

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 & benchmark comparison

CapabilityVeanUIAnt Design MenuElement Plus MenuRadix Menubar
Aria/styled split✅ @vean/aria/menubar + scv()❌ single package❌ single package✅ @radix-ui/react-menubar
Data-driven compact API✅ MenubarCompact + nested items✅ items✅ items❌ JSX composition
Top-level triggers✅ click / hover switch + arrows✅ click / hover✅ click / hover✅ click / hover + arrows
Horizontal roving✅ Roving Focus + loop✅✅✅
Cross-menu switching✅ ArrowRight / ArrowLeft✅✅✅
Nested submenus✅ any depth (reuses menu layer)✅ SubMenu✅ el-sub-menu✅
Link top-level items✅ href / to + target / external / disabled✅ danger etc.—✅ LinkItem
Disabled✅ per-item + compact-wide✅ disabled✅ disabled✅ disabled
Controlled mode✅ modelValue / defaultValue✅ openKeys / selectedKeys✅ default-active✅ value / onValueChange
Direction✅ LTR / RTL + logical arrow keys✅ RTL✅ RTL✅ RTL
Size variants✅ size xs…2xl✅ size✅ size—
Menu item types✅ checkbox / radio / separator / shortcut (menu layer)✅ full✅ full✅ full

Runtime considerations

  1. Open state and pointer — in the default mode (trigger="click"), top-level triggers open their menu on pointerdown; clicking the same trigger again while open closes it via the dismissable layer (“click again to collapse”). Hovering another trigger switches the open menu. With trigger="hover" the menu opens on hover; delayDuration (default 150ms) controls the open delay and skipDelayDuration (default 300ms) the no-delay re-open window.
  2. Link top-level items — items with href / to render no dropdown; clicking or keyboard activation navigates directly. Hovering a link item while a menu is open collapses the menu and moves focus to the link.
  3. Disabled semantics — item.disabled targets a single top-level item: aria-disabled, tabindex="-1", and blocked click/keyboard activation. The compact-level disabled disables every trigger (including link triggers). Disabled child items follow menu-layer semantics.
  4. Portal and positioning — dropdown content teleports to body by default (disable via portalProps.disabled). If content appears in the wrong place, check for transform / animation-container ancestors; positioning relies on getBoundingClientRect measurements.
  5. Controlled / uncontrolled — with modelValue, internal writes only emit update:modelValue and the open menu fully follows the prop; uncontrolled usage seeds the initial state with defaultValue.
  6. Focus restoration — keyboard paths (Escape / arrow switching) restore focus to the trigger precisely; pointer paths (click outside to close) do not move focus, matching the “pointer interaction does not hijack focus” convention.
  7. RTL — with dir="rtl", arrow-key semantics mirror (ArrowLeft becomes “next”) and menu layout flips via logical properties.
  8. Overflow collapsing — with collapsible, trailing items merge into the “more” menu when the content overflows its container; measurement runs against the real rendered layout, so the container’s parent must provide a fixed/constrained width (e.g. max-w-*). If the menubar sits in a flex container that does not shrink, set min-w-0 or a width constraint on the parent.

FAQ

How do I make a top-level item navigate instead of opening a dropdown?

Set href or to on the item — link top-level items render as an <a> with no dropdown; use target / external to control how the link opens.

How do I precisely control which menu is open?

Bind modelValue with v-model. The top-level item value becomes the controlled value; activation emits update:modelValue, and external changes sync the open menu. Uncontrolled usage seeds the initial state with defaultValue.

How do I disable the whole menubar or single items?

Pass disabled to SMenubar to disable everything, or set disabled: true on a single top-level item. Disabled items render aria-disabled, drop out of tab order, and block click and keyboard activation.

What is the keyboard flow?

Tab enters the menubar; ArrowLeft / ArrowRight move between triggers; Enter / Space toggle a menu and ArrowDown opens it; inside a menu, arrow keys roam items, ArrowRight / ArrowLeft switch to neighboring top-level menus, and Escape closes. Disabled items are excluded from tab order.

Can I use checkboxes or radios inside submenus?

Yes — dropdown content reuses the menu layer: item-checked slots, MenuCheckboxItem / MenuRadioItem, plus separator / shortcut are all available; pass the matching fields on child items in compact usage.

Why does the menu collapse when hovering a link item?

Link top-level items have no dropdown; on pointer enter the menubar collapses the currently open menu and moves focus to the link — matching Radix Menubar’s link-item behavior and avoiding focus lingering on the trigger of a closed menu.

How do I make the menu open on hover instead of on click?

Pass trigger="hover" to SMenubar. Hovering a trigger opens its menu (delayDuration controls the open delay, skipDelayDuration the re-open window); the pointer can move between the menubar and the menu content without accidental closes. Keyboard operation (arrows / Enter / Space / Escape) is identical in both modes.

What if there are too many menu items to fit?

Pass collapsible to SMenubar. When the menubar content is wider than its container, trailing top-level items automatically merge into a trailing “more” menu (default label More, customizable via moreLabel / moreIcon / moreProps), so the content never exceeds the container width. The collapse state recomputes automatically when the container resizes.

Changelog

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

v0.50.0

2026-10-02

Compare release

Fix

drop the stale "more" menu when collapsible is disabled

Scope: menubarAuthors: soybeanjsView commitaeac4

Style

correct syntax for open state styles in trigger

Scope: menubarAuthors: soybeanjsView commit74349

Fix

drop the stale "more" menu when collapsible is disabled

Scope: menubarAuthors: soybeanjsView commitaeac4

Style

correct syntax for open state styles in trigger

Scope: menubarAuthors: soybeanjsView commit74349

v0.30.0

2026-08-20

Compare release

Feature

support hover trigger and show ellipsis item when overflow

Scope: menubarAuthors: soybeanjsView commit5924e

Fix

prevent trigger clicks from dismissing open menus

Scope: menubarAuthors: soybeanjsView commit574b5

Docs

mark dialog/select e2e baseline fix as verified

Scope: menubarAuthors: soybeanjsView commit96d00

Docs

update menubar docs api and skills

Scope: menubarAuthors: soybeanjsView commitde78c

Feature

support hover trigger and show ellipsis item when overflow

Scope: menubarAuthors: soybeanjsView commit5924e

Fix

prevent trigger clicks from dismissing open menus

Scope: menubarAuthors: soybeanjsView commit574b5

Docs

mark dialog/select e2e baseline fix as verified

Scope: menubarAuthors: soybeanjsView commit96d00

Docs

update menubar docs api and skills

Scope: menubarAuthors: soybeanjsView commitde78c

v0.21.0

2026-05-12

Compare release

Fix

enhance focus management for link triggers and update menu interaction logic

Scope: menubarAuthors: soybeanfeView commit2cddd

v0.20.0

2026-05-12

Compare release

Optimization

remove computed class and simplify class binding

Scope: menubarAuthors: soybeanfeView commitda103