Accessible, unstyled Menubar (WAI-ARIA APG menubar): a horizontal row of menu triggers with roving focus, typeahead, and Left/Right hand-off between open menus. Menu content, items, and submenus are the shared Menu parts re-exported under Menubar names.
|
|
| Package |
@vizejs/ui/menubar |
| Maturity |
stable |
| Own the source |
vize lib pull menubar |
| Requires |
menu, collection, context, controllable-state, dismissable-layer, focus-scope, id, inert-outside, pointer-grace, portal, positioner, presence, scroll-lock, typeahead |
| Aliases |
application menu bar, menu bar, top menu |
| Covers |
WAI-ARIA menubar pattern, Radix Menubar, Reka UI Menubar |
Usage
import { Menubar, MenubarRoot, MenubarMenu, MenubarTrigger } from "@vizejs/ui/menubar";
Or copy the source into your project with vize lib pull menubar (see Source Distribution).
API
Source: src/families/menus/menubar/menubar-root.vue
Props
| Prop |
Type |
Default |
Description |
id |
string | null |
undefined |
Consumer-owned menubar id. null and undefined select a deterministic fallback. |
modelValue |
string | null |
undefined |
Controlled value of the open menu (v-model); null closes every menu. undefined selects uncontrolled behavior. |
defaultValue |
string | null |
null |
Initially open menu for uncontrolled use. |
dir |
MenuDirection |
undefined |
Reading direction: flips Left/Right arrow meaning across triggers and menus. undefined inherits DirectionProvider/LocaleProvider, then "ltr". |
loop |
boolean |
true |
Wrap Left/Right navigation from the last trigger to the first and back. |
ariaLabel |
string |
undefined |
Accessible name for the menubar. |
ariaLabelledby |
string |
undefined |
Ids that label the menubar. |
Events
| Event |
Payload |
Description |
update:modelValue |
[value: string | null] |
Fired with the requested open-menu value (supports v-model). |
value-change |
[value: string | null, previous: string | null, nativeEvent: Event | null] |
Fired after a distinct open-menu change with the previous value and native event. |
Slots
| Slot |
Slot props |
Description |
default |
MenubarSlotState |
MenubarMenu children. Receives the open-menu value. |
Source: src/families/menus/menubar/menubar-root.vue
Props
| Prop |
Type |
Default |
Description |
id |
string | null |
undefined |
Consumer-owned menubar id. null and undefined select a deterministic fallback. |
modelValue |
string | null |
undefined |
Controlled value of the open menu (v-model); null closes every menu. undefined selects uncontrolled behavior. |
defaultValue |
string | null |
null |
Initially open menu for uncontrolled use. |
dir |
MenuDirection |
undefined |
Reading direction: flips Left/Right arrow meaning across triggers and menus. undefined inherits DirectionProvider/LocaleProvider, then "ltr". |
loop |
boolean |
true |
Wrap Left/Right navigation from the last trigger to the first and back. |
ariaLabel |
string |
undefined |
Accessible name for the menubar. |
ariaLabelledby |
string |
undefined |
Ids that label the menubar. |
Events
| Event |
Payload |
Description |
update:modelValue |
[value: string | null] |
Fired with the requested open-menu value (supports v-model). |
value-change |
[value: string | null, previous: string | null, nativeEvent: Event | null] |
Fired after a distinct open-menu change with the previous value and native event. |
Slots
| Slot |
Slot props |
Description |
default |
MenubarSlotState |
MenubarMenu children. Receives the open-menu value. |
Exposed
| Member |
Type |
Description |
value |
string | null |
Value of the open menu, or null when every menu is closed. |
dir |
MenuDirection |
Resolved reading direction. |
element |
HTMLDivElement | null |
Rendered role="menubar" element. |
setValue |
(value: string | null) => boolean |
Open the menu with value (or close every menu with null). |
focus |
() => void |
Move focus to the first enabled trigger. |
Source: src/families/menus/menubar/menubar-menu.vue
Props
| Prop |
Type |
Default |
Description |
value |
string |
undefined |
Stable value identifying this menu in the menubar v-model. undefined selects a deterministic fallback. |
modal |
boolean |
false |
Make outside content inert while this menu is open. Menubars default to non-modal so hovering sibling triggers can switch menus. |
loop |
boolean |
false |
Wrap Up/Down navigation inside this menu. |
disabled |
boolean |
false |
Prevent this menu from opening; its trigger stays focusable per WAI-ARIA APG. |
Slots
| Slot |
Slot props |
Description |
default |
MenubarMenuSlotState |
MenubarTrigger and menu content. Receives this menu's open state and value. |
Exposed
| Member |
Type |
Description |
value |
string |
Stable value identifying this menu. |
open |
boolean |
Whether this menu is open. |
setOpen |
(value: boolean) => boolean |
Open this menu (entry focus on the first item) or close it. |
Source: src/families/menus/menubar/menubar-trigger.vue
Props
| Prop |
Type |
Default |
Description |
disabled |
boolean |
false |
Keep the trigger focusable but prevent it from opening its menu. |
textValue |
string |
undefined |
Typeahead text when the rendered text is not representative. |
Slots
| Slot |
Slot props |
Description |
default |
MenubarTriggerSlotState |
Trigger contents. Receives menu state, value, and roving highlight. |
Exposed
| Member |
Type |
Description |
element |
HTMLButtonElement | null |
Rendered role="menuitem" trigger. |
focus |
() => void |
Move focus (and the roving tab stop) to this trigger. |
Behavior
@vizejs/ui/menubar implements the WAI-ARIA APG menubar pattern on the shared menu core
(see ../menu/menu.behavior.md). menubar-root.vue owns the open-menu value and a roving
tab stop across triggers; each menubar-menu.vue is a non-modal menu root; menubar-trigger.vue
is a role="menuitem" button. Every row is proven by the named test in menubar.test.ts or
menubar-ssr.test.ts.
| # |
State |
Input |
Outcome |
Proven by |
| B1 |
any |
render |
role="menubar", horizontal orientation, label, menuitem triggers with aria-haspopup; one tabindex="0" stop |
renders a labelled horizontal menubar with a single roving tab stop |
| B2 |
trigger focus |
ArrowLeft/Right, Home/End, characters |
roving focus moves (wrapping by default), jumps to ends, and typeahead matches trigger text |
Left/Right move the roving focus with wrapping, Home/End jump |
| B3 |
dir="rtl" |
ArrowLeft |
moves to the next trigger |
rtl flips Left/Right across triggers |
| B4 |
trigger focus |
ArrowDown/Enter/Space, ArrowUp, Escape |
opens with the first or last item focused and updates v-model; Escape closes back to the trigger |
ArrowDown/Enter/Space open with the first item; ArrowUp with the last |
| B5 |
menu open |
ArrowRight/Left on a plain item |
closes the menu and opens the adjacent one with its first item focused, wrapping |
Right/Left inside an open menu hand off to the adjacent menu |
| B6 |
submenu in a menu |
ArrowRight / ArrowRight in submenu |
a submenu trigger consumes ArrowRight; ArrowRight on a plain submenu item hands off to the next menu |
a submenu trigger consumes Right; Left closes the submenu before handing off |
| B7 |
menu open |
ArrowRight on a focused trigger |
the next menu opens |
Right on a trigger while a menu is open opens the next menu |
| B8 |
mouse |
pointer-down / hover siblings |
pointer-down toggles; while a menu is open, hovering another trigger switches the open menu |
pointer-down toggles a menu and hovering siblings switches the open menu |
| B9 |
menu open |
render / outside pointer-down |
menubar menus are non-modal; outside pointer-down closes |
menubar menus are non-modal and close on outside pointer-down |
| B10 |
disabled menu |
navigation / activation |
its trigger remains focusable with aria-disabled and never opens |
disabled menus keep a focusable trigger that never opens |
| B11 |
controlled value |
selection / props / expose |
the prop wins until accepted; setValue and focus drive the root |
controlled value and the exposed API drive the open menu |
| B12 |
SSR |
two requests + hydrate |
byte-identical markup with a single tab stop and warning-free hydration |
renders identical menubar markup across SSR requests and hydrates cleanly |