Accessible, unstyled Menu compound primitive (WAI-ARIA APG menu and menu button). Every menu surface — DropdownMenu, ContextMenu, and Menubar — shares this core: roving focus, typeahead, submenus with pointer grace, dismissal, focus return, positioning, portals, and presence.
|
|
| Package |
@vizejs/ui/menu |
| Maturity |
stable |
| Own the source |
vize lib pull menu |
| Requires |
collection, context, controllable-state, dismissable-layer, focus-scope, id, inert-outside, pointer-grace, portal, positioner, presence, scroll-lock, typeahead |
| Aliases |
menu, action menu, submenu, menuitemcheckbox, menuitemradio |
| Covers |
WAI-ARIA menu pattern, Radix Menu, Reka UI Menu, React Aria Menu |
Usage
import { Menu, MenuRoot, MenuArrow, MenuCheckboxItem, MenuContent, MenuGroup, MenuItem, MenuItemIndicator, MenuLabel, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger } from "@vizejs/ui/menu";
Or copy the source into your project with vize lib pull menu (see Source Distribution).
API
Source: src/families/menus/menu/menu-root.vue
Props
| Prop |
Type |
Default |
Description |
id |
string | null |
undefined |
Consumer-owned base id. null and undefined select a deterministic fallback. |
open |
boolean |
undefined |
Controlled open state. undefined selects uncontrolled behavior. |
defaultOpen |
boolean |
false |
Initial open state for uncontrolled use. |
modal |
boolean |
true |
Make outside content inert and lock document scroll while open. |
dir |
MenuDirection |
undefined |
Reading direction: flips submenu arrow keys and submenu placement. undefined inherits DirectionProvider/LocaleProvider, then "ltr". |
loop |
boolean |
false |
Wrap arrow-key navigation from the last item to the first and back. |
disabled |
boolean |
false |
Prevent opening and close the menu when it becomes disabled. |
Events
| Event |
Payload |
Description |
update:open |
[value: boolean] |
Fired with the requested open value (supports v-model:open). |
open-change |
[value: boolean, previous: boolean, nativeEvent: Event | null] |
Fired after any distinct open-state request with the previous value and native event. |
Slots
| Slot |
Slot props |
Description |
default |
MenuSlotState |
Trigger and content. Receives the menu open state. |
Source: src/families/menus/menu/menu-root.vue
Props
| Prop |
Type |
Default |
Description |
id |
string | null |
undefined |
Consumer-owned base id. null and undefined select a deterministic fallback. |
open |
boolean |
undefined |
Controlled open state. undefined selects uncontrolled behavior. |
defaultOpen |
boolean |
false |
Initial open state for uncontrolled use. |
modal |
boolean |
true |
Make outside content inert and lock document scroll while open. |
dir |
MenuDirection |
undefined |
Reading direction: flips submenu arrow keys and submenu placement. undefined inherits DirectionProvider/LocaleProvider, then "ltr". |
loop |
boolean |
false |
Wrap arrow-key navigation from the last item to the first and back. |
disabled |
boolean |
false |
Prevent opening and close the menu when it becomes disabled. |
Events
| Event |
Payload |
Description |
update:open |
[value: boolean] |
Fired with the requested open value (supports v-model:open). |
open-change |
[value: boolean, previous: boolean, nativeEvent: Event | null] |
Fired after any distinct open-state request with the previous value and native event. |
Slots
| Slot |
Slot props |
Description |
default |
MenuSlotState |
Trigger and content. Receives the menu open state. |
Source: src/families/menus/menu/menu-arrow.vue
Slots
| Slot |
Slot props |
Description |
default |
MenuArrowSlotState |
Decorative arrow contents. Receives coordinates for optional custom drawing. |
Exposed
| Member |
Type |
Description |
x |
number | null |
Current arrow x coordinate when measured. |
y |
number | null |
Current arrow y coordinate when measured. |
element |
HTMLDivElement | null |
Rendered arrow element. |
Source: src/families/menus/menu/menu-checkbox-item.vue
Props
| Prop |
Type |
Default |
Description |
modelValue |
MenuCheckedState |
undefined |
Controlled checked value (v-model). undefined selects uncontrolled behavior. |
defaultValue |
MenuCheckedState |
false |
Initial checked value for uncontrolled use. |
disabled |
boolean |
false |
Block activation while keeping the item focusable. |
textValue |
string |
undefined |
Typeahead text when the rendered text is not representative. |
closeOnSelect |
boolean |
true |
Close the whole menu tree after an unprevented selection. |
Events
| Event |
Payload |
Description |
update:modelValue |
[value: boolean] |
Fired with the toggled checked value (supports v-model). |
select |
[event: MenuSelectEvent] |
Fired when the item is activated, before toggling; call preventDefault() to keep the menu open. |
Slots
| Slot |
Slot props |
Description |
default |
MenuCheckboxItemSlotState |
Item contents. Receives checked, highlight, and disabled state. |
Exposed
| Member |
Type |
Description |
element |
HTMLDivElement | null |
Rendered role="menuitem" element. |
id |
string |
Stable item id, also used as its collection key. |
highlighted |
boolean |
Whether the item owns the highlight. |
disabled |
boolean |
Whether activation is disabled. |
focus |
() => void |
Move focus (and the highlight) to this item. |
select |
(event?: Event | null) => boolean |
Activate the item as if the user selected it. |
checked |
MenuCheckedState |
Current checked value. |
Source: src/families/menus/menu/menu-content.vue
Props
| Prop |
Type |
Default |
Description |
forceMount |
boolean |
false |
Keep the content mounted while the menu is closed. |
to |
string | HTMLElement |
"body" |
CSS selector or element the menu layer is moved into. |
portalDisabled |
boolean |
false |
Render in place instead of teleporting. |
defer |
boolean |
true |
Keep content in place until the target exists, avoiding SSR mismatch. |
placement |
Placement |
"bottom-start" |
Preferred placement before collision handling. |
strategy |
PositionerStrategy |
"fixed" |
CSS positioning mode published on the floating host. |
offset |
number |
4 |
Gap on the main axis between the reference and content. |
collisionPadding |
number |
4 |
Viewport padding the content should not cross. |
arrowPadding |
number |
0 |
Inset kept between the arrow and content edges. |
flip |
boolean |
true |
Flip to the opposite side when the preferred side overflows more. |
shift |
boolean |
true |
Shift the content back into the viewport after flip. |
size |
boolean |
false |
Constrain the host and publish positioner available-size CSS variables. |
safeArea |
boolean |
false |
Keep content clear of safe-area insets. |
hide |
boolean |
true |
Hide when the reference no longer intersects the viewport. |
updateOnScroll |
boolean |
true |
Recalculate while ancestors scroll. |
updateOnResize |
boolean |
true |
Recalculate when the viewport resizes. |
viewport |
Rect |
undefined |
Viewport used for flip, shift, and hide. |
closeOnEscape |
boolean |
true |
Let Escape close the menu. |
closeOnPointerDownOutside |
boolean |
true |
Let outside pointer-down close the menu. |
closeOnFocusOutside |
boolean |
true |
Let outside focus movement close the menu. |
ariaLabel |
string |
undefined |
Accessible name when the trigger does not label the menu. |
ariaLabelledby |
string |
undefined |
Ids that label the menu; defaults to the trigger id when a trigger exists. |
Events
| Event |
Payload |
Description |
open-auto-focus |
[event: MenuAutoFocusEvent] |
Fired before automatic entry focus; preventable. |
close-auto-focus |
[event: MenuAutoFocusEvent] |
Fired before focus returns to the trigger; preventable. |
escape-key-down |
[event: MenuEscapeKeyDownEvent] |
Fired before Escape closes the menu; preventable. |
pointer-down-outside |
[event: MenuPointerDownOutsideEvent] |
Fired before an outside pointer-down closes the menu; preventable. |
focus-outside |
[event: MenuFocusOutsideEvent] |
Fired before outside focus closes the menu; preventable. |
interact-outside |
[event: MenuInteractOutsideEvent] |
Fired before any outside interaction closes the menu; preventable. |
dismiss |
[event: MenuDismissEvent] |
Fired after an unprevented dismissal request. |
Slots
| Slot |
Slot props |
Description |
default |
MenuContentSlotState |
Menu items. Receives open state and the resolved placement. |
Exposed
| Member |
Type |
Description |
element |
HTMLDivElement | null |
Rendered role="menu" element. |
open |
boolean |
Whether the content is open. |
state |
MenuState |
Stable state token. |
focusFirst |
() => HTMLElement | null |
Focus the first navigable item. |
focusLast |
() => HTMLElement | null |
Focus the last navigable item. |
focusContent |
() => void |
Focus the menu container and clear the highlight. |
Source: src/families/menus/menu/menu-group.vue
Slots
| Slot |
Slot props |
Description |
default |
— |
Grouped items, usually led by a MenuLabel that names the group. |
Source: src/families/menus/menu/menu-item.vue
Props
| Prop |
Type |
Default |
Description |
disabled |
boolean |
false |
Block activation. The item stays focusable and announced as disabled (WAI-ARIA APG). |
textValue |
string |
undefined |
Typeahead text when the rendered text is not representative. |
closeOnSelect |
boolean |
true |
Close the whole menu tree after an unprevented selection. |
Events
| Event |
Payload |
Description |
select |
[event: MenuSelectEvent] |
Fired when the item is activated; call preventDefault() to keep the menu open. |
Slots
| Slot |
Slot props |
Description |
default |
MenuItemSlotState |
Item contents. Receives highlight and disabled state. |
Exposed
| Member |
Type |
Description |
element |
HTMLDivElement | null |
Rendered role="menuitem" element. |
id |
string |
Stable item id, also used as its collection key. |
highlighted |
boolean |
Whether the item owns the highlight. |
disabled |
boolean |
Whether activation is disabled. |
focus |
() => void |
Move focus (and the highlight) to this item. |
select |
(event?: Event | null) => boolean |
Activate the item as if the user selected it. |
Source: src/families/menus/menu/menu-item-indicator.vue
Props
| Prop |
Type |
Default |
Description |
forceMount |
boolean |
false |
Keep the indicator visible and its slot rendered while unchecked, for exit animations or glyphs that style the unchecked state themselves. |
Slots
| Slot |
Slot props |
Description |
default |
MenuItemIndicatorSlotState |
Indicator glyph. Receives the owning item's checked-state token. |
Source: src/families/menus/menu/menu-label.vue
Props
| Prop |
Type |
Default |
Description |
id |
string | null |
undefined |
Consumer-owned label id. null and undefined select a deterministic fallback. |
Slots
| Slot |
Slot props |
Description |
default |
— |
Visible label text. Inside a MenuGroup it names that group. |
Source: src/families/menus/menu/menu-radio-group.vue
Props
| Prop |
Type |
Default |
Description |
modelValue |
Value | null |
undefined |
Controlled value (v-model). undefined selects uncontrolled behavior; null clears. |
defaultValue |
Value | null |
null |
Initial value for uncontrolled use. |
disabled |
boolean |
false |
Block activation of every radio item in the group. |
equals |
(left: Value, right: Value) => boolean |
Object.is |
Equality used to decide which item is checked (for example, compare object ids). |
Events
| Event |
Payload |
Description |
update:modelValue |
[value: Value | null] |
Fired with the newly selected value (supports v-model). |
value-change |
[value: Value | null, previous: Value | null, nativeEvent: Event | null] |
Fired after a distinct value is selected, with the previous value and native event. |
Slots
| Slot |
Slot props |
Description |
default |
MenuRadioGroupSlotState<Value> |
Radio items. Receives the current value. |
Exposed
| Member |
Type |
Description |
value |
Value | null |
Current group value. |
setValue |
(value: Value | null) => boolean |
Request a group value; returns whether it changed. |
Source: src/families/menus/menu/menu-radio-item.vue
Props
| Prop |
Type |
Default |
Description |
value (required) |
Value |
undefined |
Value committed to the enclosing MenuRadioGroup when this item is selected. |
disabled |
boolean |
false |
Block activation while keeping the item focusable. |
textValue |
string |
undefined |
Typeahead text when the rendered text is not representative. |
closeOnSelect |
boolean |
true |
Close the whole menu tree after an unprevented selection. |
Events
| Event |
Payload |
Description |
select |
[event: MenuSelectEvent] |
Fired when the item is activated, before the group value changes; preventable. |
Slots
| Slot |
Slot props |
Description |
default |
MenuRadioItemSlotState |
Item contents. Receives checked, highlight, and disabled state. |
Exposed
| Member |
Type |
Description |
element |
HTMLDivElement | null |
Rendered role="menuitem" element. |
id |
string |
Stable item id, also used as its collection key. |
highlighted |
boolean |
Whether the item owns the highlight. |
disabled |
boolean |
Whether activation is disabled. |
focus |
() => void |
Move focus (and the highlight) to this item. |
select |
(event?: Event | null) => boolean |
Activate the item as if the user selected it. |
checked |
boolean |
Whether this item holds the group value. |
Source: src/families/menus/menu/menu-separator.vue
Source: src/families/menus/menu/menu-sub.vue
Props
| Prop |
Type |
Default |
Description |
id |
string | null |
undefined |
Consumer-owned submenu base id. null and undefined select a deterministic fallback. |
open |
boolean |
undefined |
Controlled open state. undefined selects uncontrolled behavior. |
defaultOpen |
boolean |
false |
Initial open state for uncontrolled use (only honored while the parent is open). |
disabled |
boolean |
false |
Prevent the submenu from opening; its trigger stays focusable but inert. |
Events
| Event |
Payload |
Description |
update:open |
[value: boolean] |
Fired with the requested submenu open value (supports v-model:open). |
open-change |
[value: boolean, previous: boolean, nativeEvent: Event | null] |
Fired after any distinct open-state request with the previous value and native event. |
Slots
| Slot |
Slot props |
Description |
default |
MenuSubSlotState |
MenuSubTrigger and MenuSubContent. Receives the submenu open state. |
Exposed
| Member |
Type |
Description |
open |
boolean |
Whether the submenu is open. |
state |
MenuState |
Stable state token. |
triggerId |
string |
Id wired to the submenu trigger. |
contentId |
string |
Id wired to the submenu content. |
setOpen |
(value: boolean, event?: Event | null) => boolean |
Request the submenu open value. |
Source: src/families/menus/menu/menu-sub-content.vue
Props
| Prop |
Type |
Default |
Description |
forceMount |
boolean |
false |
Keep the submenu mounted while closed. |
to |
string | HTMLElement |
"body" |
CSS selector or element the submenu layer is moved into. |
portalDisabled |
boolean |
false |
Render in place instead of teleporting. |
defer |
boolean |
true |
Keep content in place until the target exists, avoiding SSR mismatch. |
strategy |
PositionerStrategy |
"fixed" |
CSS positioning mode published on the floating host. |
offset |
number |
0 |
Gap between the submenu trigger and the submenu. |
collisionPadding |
number |
4 |
Viewport padding the submenu should not cross. |
arrowPadding |
number |
0 |
Inset kept between the arrow and content edges. |
flip |
boolean |
true |
Flip to the opposite side when the reading-direction side overflows more. |
shift |
boolean |
true |
Shift the submenu back into the viewport after flip. |
size |
boolean |
false |
Constrain the host and publish positioner available-size CSS variables. |
safeArea |
boolean |
false |
Keep content clear of safe-area insets. |
hide |
boolean |
true |
Hide when the trigger no longer intersects the viewport. |
updateOnScroll |
boolean |
true |
Recalculate while ancestors scroll. |
updateOnResize |
boolean |
true |
Recalculate when the viewport resizes. |
viewport |
Rect |
undefined |
Viewport used for flip, shift, and hide. |
closeOnEscape |
boolean |
true |
Let Escape close this submenu and return focus to its trigger. |
closeOnPointerDownOutside |
boolean |
true |
Let outside pointer-down close the submenu (and the tree when outside every menu). |
closeOnFocusOutside |
boolean |
true |
Let outside focus movement close the submenu. |
ariaLabel |
string |
undefined |
Accessible name overriding the submenu trigger label. |
Events
| Event |
Payload |
Description |
open-auto-focus |
[event: MenuAutoFocusEvent] |
Fired before automatic entry focus; preventable. |
close-auto-focus |
[event: MenuAutoFocusEvent] |
Fired before automatic focus restoration; preventable. |
escape-key-down |
[event: MenuEscapeKeyDownEvent] |
Fired before Escape closes the submenu; preventable. |
pointer-down-outside |
[event: MenuPointerDownOutsideEvent] |
Fired before an outside pointer-down closes the submenu; preventable. |
focus-outside |
[event: MenuFocusOutsideEvent] |
Fired before outside focus closes the submenu; preventable. |
interact-outside |
[event: MenuInteractOutsideEvent] |
Fired before any outside interaction closes the submenu; preventable. |
dismiss |
[event: MenuDismissEvent] |
Fired after an unprevented dismissal request. |
Slots
| Slot |
Slot props |
Description |
default |
MenuContentSlotState |
Submenu items. Receives open state and the resolved placement. |
Source: src/families/menus/menu/menu-sub-trigger.vue
Props
| Prop |
Type |
Default |
Description |
disabled |
boolean |
false |
Block opening the submenu while keeping the trigger focusable. |
textValue |
string |
undefined |
Typeahead text when the rendered text is not representative. |
Slots
| Slot |
Slot props |
Description |
default |
MenuSubTriggerSlotState |
Trigger contents. Receives submenu open state plus highlight and disabled state. |
Source: src/families/menus/menu/menu-trigger.vue
Props
| Prop |
Type |
Default |
Description |
disabled |
boolean |
false |
Remove the trigger from activation and sequential keyboard focus. |
ariaLabel |
string |
undefined |
Accessible name when no visible label supplies one. |
Events
| Event |
Payload |
Description |
click |
[nativeEvent: MouseEvent] |
Fired before a click toggles the menu. Call preventDefault() to keep state unchanged. |
keydown |
[nativeEvent: KeyboardEvent] |
Fired before keyboard handling. Call preventDefault() to skip the built-in keys. |
Slots
| Slot |
Slot props |
Description |
default |
MenuSlotState |
Trigger contents. Receives the menu open state. |
Exposed
| Member |
Type |
Description |
element |
HTMLButtonElement | null |
Rendered native button. |
focus |
(options?: FocusOptions) => void |
Move focus to the trigger. |
Behavior
Normative state x input -> outcome table for the shared menu core
(@vizejs/ui/menu), which also powers dropdown-menu, context-menu, and
menubar. It follows the WAI-ARIA APG menu button
and menu patterns. Every row is proven
by the named test in menu.test.ts, menu-keyboard.test.ts, menu-pointer.test.ts, or
menu-ssr.test.ts; compile-only guarantees live in menu.types.test-d.ts.
Components: menu-root.vue, menu-trigger.vue, menu-content.vue, menu-item.vue,
menu-checkbox-item.vue, menu-radio-group.vue, menu-radio-item.vue,
menu-item-indicator.vue, menu-group.vue, menu-label.vue, menu-separator.vue,
menu-sub.vue, menu-sub-trigger.vue, menu-sub-content.vue, menu-arrow.vue.
| # |
State |
Input |
Outcome |
Proven by |
| M1 |
closed |
render / pointer click on trigger |
native button with aria-haspopup="menu", aria-expanded, aria-controls while open; content is role="menu" labelled by the trigger and focused itself |
renders menu-button ARIA, deterministic ids, and pointer-opened content |
| M2 |
closed, trigger focus |
Enter / Space / ArrowDown / ArrowUp |
opens and focuses (and highlights) the first item, or the last item for ArrowUp |
trigger ${key} opens the menu and focuses ${expected} (four cases) |
| M3 |
open |
ArrowDown/Up, Home/End, PageDown/PageUp |
roving focus moves one item or to either end; no wrap unless loop |
arrow, Home/End, and Page keys move focus without wrapping by default |
| M4 |
open, loop |
ArrowUp on first / ArrowDown on last |
focus wraps |
loop wraps arrow navigation at both ends |
| M5 |
open |
printable characters |
locale-aware typeahead: prefix match, repeated letters cycle, textValue overrides rendered text |
typeahead matches prefixes, cycles repeated letters, and honors textValue |
| M6 |
open, pending query |
Space |
extends the query instead of selecting; Space selects once the query expires |
Space extends a pending typeahead query instead of selecting |
| M7 |
open (any depth) |
Tab |
the whole tree closes and focus returns to the trigger |
Tab closes the whole menu tree and returns focus to the trigger |
| M8 |
item highlighted |
Enter / click |
select fires with a preventable MenuSelectEvent; unprevented selection closes the tree and returns focus; preventDefault() keeps it open |
selecting an item emits a preventable select, closes the tree, and returns focus |
| M9 |
disabled item |
arrows / Enter / click |
stays focusable (APG), exposes aria-disabled and data-disabled, never selects |
disabled items stay focusable, announce aria-disabled, and never select |
| M10 |
checkbox item |
activation |
toggles aria-checked (mixed for indeterminate), data-state, indicator visibility, v-model; closeOnSelect=false keeps the menu open |
checkbox items toggle aria-checked, indicators, and honor closeOnSelect |
| M11 |
radio group <Value> |
activation |
commits the item's typed value, compares with equals, emits update:modelValue and value-change |
radio groups select generic values with custom equality |
| M12 |
controlled open |
trigger activation |
emits update:open and open-change; rendered state follows the prop only |
controlled open emits requests without opening until the parent accepts |
| M13 |
open |
outside pointer-down / Escape |
outside pointer closes without stealing focus; Escape closes and returns focus; closeOn* props disable either path |
outside pointer-down closes without stealing focus; Escape closes and returns focus |
| M14 |
open, modal |
render |
outside content is inert and scroll-locked (trigger stays live); non-modal menus leave the page interactive |
modal menus inert outside content; non-modal menus leave the page interactive |
| M15 |
disabled root |
activation / becoming disabled |
refuses to open and closes an open menu |
disabled roots refuse to open and close when disabled while open |
| M16 |
closed, forceMount |
render |
content stays mounted with hidden and data-state="closed"; no document controllers |
force-mounted closed content stays hidden and inactive |
| M17 |
any |
expose |
root openMenu/close/toggle/setOpen and ids; content focusFirst/focusLast/focusContent |
exposes root and content imperative APIs |
| M18 |
submenu trigger |
ArrowRight / Enter / Space |
opens the submenu and focuses its first item; ArrowLeft or Escape closes only the submenu and refocuses its trigger |
submenu keys: ArrowRight/Enter open, ArrowLeft/Escape close to the sub trigger |
| M19 |
dir="rtl" |
ArrowLeft / ArrowRight |
open/close keys swap and the submenu is placed on the left |
rtl flips submenu arrow keys and placement |
| M20 |
disabled MenuSub |
activation |
sub trigger stays focusable with aria-disabled and never opens |
disabled submenu triggers stay focusable but do not open |
| M21 |
open, mouse |
pointer move / leave on items |
hover highlights (focuses) items; leaving clears the highlight back to the menu |
hovering items moves the highlight; leaving an item clears it |
| M22 |
open |
hover disabled item / touch move |
disabled items never take the highlight; touch pointers never highlight |
hovering a disabled item clears the highlight; touch pointers never highlight |
| M23 |
open, mouse |
hover submenu trigger |
opens the submenu without moving focus into it; hovering submenu items highlights them |
hovering a submenu trigger opens it without moving focus into it |
| M24 |
submenu open |
pointer travels toward the submenu |
the pointer-grace safe triangle keeps the submenu open and suppresses sibling highlight; leaving it highlights the sibling and closes the submenu |
pointer grace keeps the submenu open along the safe triangle and closes it outside |
| M25 |
grace armed |
300 ms elapse |
the triangle expires even if the pointer rests inside it |
pointer grace expires after its delay |
| M26 |
submenu open |
enter submenu / outside pointer-down |
entering clears the grace; pointer-down outside every level closes the tree |
entering the submenu clears the grace; clicking outside every menu closes the tree |
| M27 |
submenu open |
pointer-down in the parent menu |
closes only the submenu |
pointer-down inside the parent menu closes only the submenu |
| M28 |
submenu open |
select submenu item |
selection closes every level |
clicking a submenu item selects it and closes every level |
| M29 |
submenu closed |
pointer click on submenu trigger |
opens the submenu |
clicking a submenu trigger with a pointer opens it |
| M30 |
SSR, open |
two isolated requests |
byte-identical markup, content rendered in place, no inert/scroll-lock/highlight side effects |
renders deterministic open menu markup on the server |
| M31 |
SSR markup |
hydrate |
no mismatch diagnostics, root node reused, then portal and focus activate |
hydrates without mismatches and then activates focus |
Extension hooks
| Hook |
Values |
| parts |
trigger, content-host, content, sub-content-host, sub-content, item, sub-trigger, item-indicator, group, radio-group, label, separator, arrow |
| data |
data-vize-ui, data-state (open/closed, or checked/unchecked/indeterminate), data-highlighted, data-disabled, data-menu-kind, data-modal, data-side, data-align, data-placement, data-top-layer |
| CSS vars |
Positioner variables such as --vize-ui-positioner-available-width when size is enabled |
| composable |
useMenuRoot() builds custom root surfaces on the same tree/level contract |