Navigation

Navigation

A nested, collapsible navigation tree for a table of contents or docs sidebar.

html
<UiNavigation :navigation="..." />

Navigation

required

navigation is the tree to render. An item can nest children, carry a badge, or be a label/separator rather than a link.

Items default to type: 'link' (a normal navigable/collapsible row) — set type: 'label' for a non-interactive section heading or type: 'separator' for a divider line, the same discriminated pattern MenuItem uses for DropdownMenu/ContextMenu.

label/separator items can appear anywhere in navigation or any children array, at any depth — they're just skipped over by the active-path/expansion tracking rather than needing special-casing there.

Give items a value when the navigation switches a panel in place rather than changing the page — SettingsModal is built on exactly that. A path wins if an item somehow has both.

Selecting a value item that also has children expands it as well, since picking a collapsed parent and seeing nothing open below it reads as broken; the caret still collapses it again.

Model value

modelValue is the selected item. Give items a value instead of a path and they become buttons matched against this — for a navigation that switches a panel in place rather than changing route.

Showing the general panel — no route change.

Color

color is the active item's color.

neutral
primary
success
warning
error
info

An item's active state comes from whichever of path/value it carries: path matches against the real current route (so color's effect is only visible on the page you're actually viewing), while value matches against v-model and renders the row as a button that emits select instead of a link. Both kinds can sit in the same tree.

Item badges are colored by badgeColor (default primary), not by color — a count stays an accent on an otherwise neutral list. Pass :badge-color="color" to tie the two back together.

Badge color

badgeColor is kept separate from color so a count still reads as an accent when the active item is tinted something else.

Variant

variant sets how much surface the rows carry. solid gives idle rows a neutral background and fills the active one; subtle rings them; soft tints them lightly; ghost, the default, leaves idle rows bare and only marks the active item.

solid
subtle
soft
ghost

variant (solid/subtle/soft/ghost, default ghost) sets the idle row's chrome — always neutral-toned regardless of color — while the active item gets that same variant's intensity but tinted with color. Unlike Button's ghost, the active row still shows the soft tier's background even under ghost — an active item with no background at all would be indistinguishable from an idle one.


API Reference

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

Props

Prop
Type
Default
Description
navigationrequired
NavigationItem[]
The navigation tree to render; each item can optionally nest its own `children`.
string
The `value` of the selected item, for navigations that switch a panel in place instead of changing the route — bind with `v-model`. Items carrying a `path` keep tracking the real route regardless, so the two styles can be mixed in one tree.
"neutral" | "primary" | "secondary" | "success" | "error" | "warning" | "info" | "pending"
'neutral'
The color of the active item.
"neutral" | "primary" | "secondary" | "success" | "error" | "warning" | "info" | "pending"
'primary'
The color of every item's `badge`, kept separate from `color` so a count still reads as an accent on an otherwise neutral list.
"solid" | "subtle" | "soft" | "ghost"
'ghost'
The visual style of the active item.

Emits

Event
Payload
Description
update:modelValue
[value: string]
select
[item: NavigationItem]

Types

ts
type NavigationColor = "neutral" | "primary" | "secondary" | "success" | "error" | "warning" | "info" | "pending";
ts
type NavigationVariant = "solid" | "subtle" | "soft" | "ghost";
ts
interface NavigationItem {
    title: string;
    path?: string;
    value?: string;
    icon?: string;
    badge?: string | number;
    children?: NavigationItem[];
    defaultOpen?: boolean;
    /**
     * @defaultValue 'link'
     */
    type?: "link" | "label" | "separator";
}
ts
interface NavigationContext {
    isExpanded: (key: string) => boolean;
    toggle: (key: string) => void;
    isActive: (item: NavigationItem) => boolean;
    select: (item: NavigationItem) => void;
    color: ComputedRef<NavigationColor>;
    badgeColor: ComputedRef<NavigationColor>;
    variant: ComputedRef<NavigationVariant>;
}