Vize

Navigation Menu

Accessible, unstyled site navigation with hover-intent flyouts, an indicator, and a measured viewport.

Package @vizejs/ui/navigation-menu
Maturity stable
Own the source vize lib pull navigation-menu
Requires collection, context, controllable-state, id
Aliases site navigation, mega menu, navbar, flyout navigation, disclosure navigation
Covers WAI-ARIA disclosure navigation pattern, Radix Navigation Menu, Reka UI Navigation Menu, Ark UI Navigation Menu

Usage

import { NavigationMenu, NavigationMenuRoot, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport } from "@vizejs/ui/navigation-menu";

Or copy the source into your project with vize lib pull navigation-menu (see Source Distribution).

API

Source: src/families/navigation/navigation-menu/navigation-menu-root.vue

Props

Prop Type Default Description
id string | null undefined Consumer-owned base id. null and undefined select a deterministic fallback.
modelValue NavigationMenuValue undefined Controlled open item value (v-model). undefined selects uncontrolled behavior.
defaultValue NavigationMenuValue null Initially open item value for uncontrolled use.
delayDuration number 200 Hover time in milliseconds before a pointer opens a flyout.
skipDelayDuration number 300 Window in milliseconds after closing during which hovering another trigger opens instantly.
closeDelay number 150 Grace time in milliseconds before a pointer leaving the trigger or flyout closes it.
orientation NavigationMenuOrientation "horizontal" Layout axis of the top-level list, used for arrow keys and the open key.
dir NavigationMenuDirection undefined Reading direction for horizontal arrow keys and motion attributes. undefined inherits DirectionProvider/LocaleProvider, then "ltr".
ariaLabel string undefined Accessible name of the navigation landmark.
ariaLabelledby string undefined Space-separated ids that label the landmark.

Events

Event Payload Description
update:modelValue [value: NavigationMenuValue] Fired with the next open item value whenever a flyout opens or closes.
change [ value: NavigationMenuValue, previous: NavigationMenuValue, reason: NavigationMenuChangeReason, ] Fired after a distinct open-value change with the input that caused it.

Slots

Slot Slot props Description
default NavigationMenuSlotState List, item, and viewport children. Receives the open value and axis.

Exposed

Member Type Description
close —
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.
open —
value —

Source: src/families/navigation/navigation-menu/navigation-menu-root.vue

Props

Prop Type Default Description
id string | null undefined Consumer-owned base id. null and undefined select a deterministic fallback.
modelValue NavigationMenuValue undefined Controlled open item value (v-model). undefined selects uncontrolled behavior.
defaultValue NavigationMenuValue null Initially open item value for uncontrolled use.
delayDuration number 200 Hover time in milliseconds before a pointer opens a flyout.
skipDelayDuration number 300 Window in milliseconds after closing during which hovering another trigger opens instantly.
closeDelay number 150 Grace time in milliseconds before a pointer leaving the trigger or flyout closes it.
orientation NavigationMenuOrientation "horizontal" Layout axis of the top-level list, used for arrow keys and the open key.
dir NavigationMenuDirection undefined Reading direction for horizontal arrow keys and motion attributes. undefined inherits DirectionProvider/LocaleProvider, then "ltr".
ariaLabel string undefined Accessible name of the navigation landmark.
ariaLabelledby string undefined Space-separated ids that label the landmark.

Events

Event Payload Description
update:modelValue [value: NavigationMenuValue] Fired with the next open item value whenever a flyout opens or closes.
change [ value: NavigationMenuValue, previous: NavigationMenuValue, reason: NavigationMenuChangeReason, ] Fired after a distinct open-value change with the input that caused it.

Slots

Slot Slot props Description
default NavigationMenuSlotState List, item, and viewport children. Receives the open value and axis.

Exposed

Member Type Description
element HTMLElement | null Rendered navigation landmark.
value NavigationMenuValue Open item value.
open (value: string) => boolean Open one item's flyout immediately.
close () => boolean Close the open flyout immediately.

Source: src/families/navigation/navigation-menu/navigation-menu-content.vue

Props

Prop Type Default Description
forceMount boolean false Keep closed flyout content rendered (inside the hidden container) for exit animations or crawlable links. Without it, closed flyouts keep an empty hidden container.

Slots

Slot Slot props Description
default NavigationMenuItemSlotState Flyout content, usually NavigationMenuLink lists. Receives the open state.

Source: src/families/navigation/navigation-menu/navigation-menu-indicator.vue

Slots

Slot Slot props Description
default NavigationMenuMeasuredSlotState Optional indicator content such as an arrow. Receives the open value.

Source: src/families/navigation/navigation-menu/navigation-menu-item.vue

Props

Prop Type Default Description
value (required) string required Stable item value used as the open value of its flyout.

Slots

Slot Slot props Description
default NavigationMenuItemSlotState Trigger, content, or a plain link. Receives the open state of this item.

Source: src/families/navigation/navigation-menu/navigation-menu-link.vue

Props

Prop Type Default Description
as PrimitiveAs "a" Native element, custom element, or router component to render.
href string undefined Native link destination. Router components can receive their own route attrs instead.
active boolean false Whether the link represents the current page (aria-current="page").

Events

Event Payload Description
select [nativeEvent: MouseEvent] Fired when the link is activated. Call preventDefault() to keep the flyout open.

Slots

Slot Slot props Description
default NavigationMenuLinkSlotState Link content. Receives whether it represents the current page.

Source: src/families/navigation/navigation-menu/navigation-menu-list.vue

Slots

Slot Slot props Description
default { /** Layout axis of the list. */ readonly orientation: NavigationMenuOrientation; } NavigationMenuItem children. Receives the list axis.

Source: src/families/navigation/navigation-menu/navigation-menu-trigger.vue

Props

Prop Type Default Description
disabled boolean false Disable the trigger and its flyout.

Slots

Slot Slot props Description
default NavigationMenuItemSlotState Trigger label. Receives the open state of the owning item.

Source: src/families/navigation/navigation-menu/navigation-menu-viewport.vue

Slots

Slot Slot props Description
default NavigationMenuMeasuredSlotState Optional backdrop content. Receives the open value.

Behavior

Normative state x input -> outcome table for the @vizejs/ui/navigation-menu parts: navigation-menu-root.vue, navigation-menu-list.vue, navigation-menu-item.vue, navigation-menu-trigger.vue, navigation-menu-content.vue, navigation-menu-link.vue, navigation-menu-indicator.vue, and navigation-menu-viewport.vue. Every row is proven by the named test in navigation-menu.test.ts or navigation-menu-ssr.test.ts; compile-only guarantees live in navigation-menu.types.test-d.ts.

The menu follows the APG disclosure navigation pattern (not role="menu"): a labelled <nav> with a <ul> of items, native <button aria-expanded aria-controls> triggers, and flyouts rendered inline after their trigger so the native tab order reaches them. The viewport is a measured backdrop that publishes --vize-navigation-menu-viewport-width/height; the indicator publishes --vize-navigation-menu-indicator-offset/size. Both are measured on the client only.

ID State Input Outcome Evidence
N1 closed render labelled nav, deterministic trigger/content ids, closed flyouts unmounted, aria-current links renders a labelled disclosure navigation with wired triggers and closed flyouts
N2 any trigger click toggles the flyout inline after the trigger and reports toggle click toggles a flyout inline after its trigger
N3 mouse or pen hover, move, leave, re-enter opens after delayDuration, switches instantly, closes after closeDelay, skip window reopens hover opens after the delay, skips it between triggers, and closes after a grace period
N4 touch pointerenter hover intent is ignored; touch uses click touch pointers never open on hover
N5 focus on a list entry arrows, Home, End, open key roving between triggers and top-level links (wrapping); ArrowDown opens and focuses the flyout arrow keys move between top-level entries and the open key enters the flyout
N6 open Escape, outside pointer, focus out, link dismisses; Escape restores focus to the trigger; flyout links close with reason link Escape, outside pointerdown, focus leaving, and link selection dismiss the flyout
N7 switching items open another item, forceMount data-motion reports from/to start/end; force-mounted flyouts stay hidden while closed motion attributes follow the direction between items and forceMount keeps hidden flyouts
N8 controlled / exposed root click, setProps, open/close the parent owns the open value; imperative open/close report distinct changes controlled values wait for the parent and the root exposes open/close
N9 open measure indicator and viewport publish CSS variables for the open item and clear them when closed the indicator and viewport publish geometry for the open item
N10 disabled trigger click, hover, open key the flyout never opens disabled triggers ignore click, hover, and the open key
N11 missing provider setup parts fail closed with the shared context diagnostic compound parts require matching providers
N12 SSR and hydration isolated render/mount default-open flyouts render, geometry is omitted, hydration has no warnings navigation-menu-ssr.test.ts
N13 link href / as render script-capable hrefs are dropped; as renders router or custom elements links drop script-capable hrefs and render custom elements