Navigation

NavigationMenu

A row (or stack) of triggers/links, with children opening a panel of grouped links in a shared, animated viewport.

html
<UiNavigationMenu :items="..." />

Items

required

items is the top-level triggers. An item with children opens a panel; one with a to is a plain link.

Only items with a non-empty children array become triggers with a panel — an item with just to renders as a plain Link, same discriminator DropdownMenu uses for submenus.

The viewport resizes and cross-fades between panels, sliding left/right based on whether the newly active item sits after or before the previously active one in items — matching Reka's directional motion, though panels swap sequentially (mode="out-in") rather than truly overlapping mid-slide.

Model value

modelValue sets which item's panel is open, two-way bound — for opening one from outside the menu.

Default value

defaultValue sets which panel starts open when uncontrolled.

Orientation

orientation lays the triggers in a row or a column. vertical runs them down a column and flies the same floating panel out to the side — a sidebar menu rather than a header one.

Both orientations use the same floating viewport: horizontal drops it below the bar, vertical flies it out to the side. The panel stays pinned to the nav's edge in both, so switching triggers resizes and cross-fades it in place rather than moving it to follow the active item — a long vertical stack keeps its panel top-aligned.

Trigger

trigger decides what opens a panel. hover opens on approach; click waits for a deliberate press, which is kinder on touch and on a menu that's easy to brush past.

trigger="hover" (default) still opens instantly on click too, and once one panel is open, hovering another trigger switches immediately, skipping delayDuration — that only applies to the first hover with nothing already open.

The gap between a trigger and its panel is a fixed ~10px hover bridge, not Reka's precise pointer-triangle safe zone — moving the pointer slowly through it can still close the menu.

Delay duration

delayDuration sets how long a hovered trigger waits before opening, when no other panel is already open. Zero opens instantly.

Skip delay duration

skipDelayDuration is the grace period after a panel closes: hovering another trigger inside that window skips delayDuration and opens at once, so moving along a menu bar feels continuous rather than stuttering.

Custom panel content

Give an item a slot name and render that slot to put arbitrary markup in its panel.

Because the panel floats rather than expanding inline, a vertical menu needs horizontal room beside it — inside a container with overflow: hidden and no space to the right, the panel will be clipped.


API Reference

Generated from the component's source — props, slots and emits as the component actually declares them.

Props

Prop
Type
Default
Description
itemsrequired
NavigationMenuItem[]
The top-level items to render as triggers/links.
string | number
The currently open item's value. Omit this to let the menu manage its own open state internally (starting from `defaultValue`); pass it to fully control which panel is open yourself.
string | number
The initially open item when uncontrolled.
"horizontal" | "vertical"
'horizontal'
The layout direction of the top-level item list. `vertical` expands panels inline instead of in a floating viewport.
"hover" | "click"
'hover'
Whether hovering a trigger opens its panel, or only clicking does. Either way, clicking a trigger always toggles it immediately.
number
200
Milliseconds a hovered trigger waits before opening, when no other panel is already open.
number
300
Milliseconds after closing during which hovering another trigger skips `delayDuration` and opens instantly, so quickly sweeping across the menu still feels responsive.

Slots

Slot
activeItem.slot ?? 'content'

Emits

Event
Payload
Description
update:modelValue
[value: string | number | undefined]

Types

ts
interface NavigationMenuItem {
    /**
     * The trigger's/link's label text.
     */
    label?: string;

    /**
     * Name of the icon displayed before the label.
     */
    icon?: string;

    /**
     * Secondary text shown under the label — only used for items rendered inside a panel, not
     * top-level triggers.
     */
    description?: string;

    /**
     * The route or URL this item navigates to. Renders as a plain link with no panel when set
     * without `children`.
     */
    to?: string;

    /**
     * The target attribute for the link (e.g. `_blank`).
     */
    target?: string;

    /**
     * Forces the active (current-page) styling, overriding the automatic route-match check `Link`
     * does on its own.
     * @defaultValue false
     */
    active?: boolean;

    /**
     * Disables interaction with this item.
     * @defaultValue false
     */
    disabled?: boolean;

    /**
     * Renders this entry as a non-interactive group heading or a divider instead of a link/trigger.
     */
    type?: "label" | "separator";

    /**
     * Sub-items rendered in this item's panel, turning it into a trigger instead of a plain link.
     * Grouped into columns the same way `DropdownMenu`'s `children` are.
     */
    children?: NavigationMenuItem[] | NavigationMenuItem[][];

    /**
     * Name of the slot rendering this item's panel content, instead of the default grid-of-links layout.
     */
    slot?: string;

    /**
     * Unique value identifying this item. Falls back to its index, so set this explicitly if items
     * can be reordered/filtered.
     */
    value?: string | number;

    /**
     * Called when this item (a plain link, or a link inside a panel) is selected.
     */
    onSelect?: (e: Event) => void;
}