Skip to content

Navigation

INavigationMenu

A horizontal app nav where an entry can open a panel of links. An entry with its own items is a panel trigger; everything else is a plain link.

Panels

Give an entry items and it becomes a trigger. Every panel shares one viewport, so the panel resizes and slides as you move between triggers.

description is a second line under the label and shows only inside a panel. columns splits a panel into two or three — set it on the menu for every panel, or on one entry to override it there, as "Records" does above.

Vertical

The same data laid out as a column. For a primary side navigation with sections, badges and a collapse mode, use ISidebar.

Opening on click

Panels open on hover after delayDuration milliseconds. disableHoverTrigger switches them to click, which is what a touch-first app wants.

Props

PropTypeDefaultDescription
itemsNavigationMenuEntry[]Top-level entries; one with items opens a panel
orientation'horizontal' | 'vertical''horizontal'Layout of the top-level list
columns1 | 2 | 31Columns in a panel; an entry can override it
labelstring'Main'Accessible name for the navigation landmark
delayDurationnumberMilliseconds a pointer must rest before a panel opens
disableHoverTriggerbooleanOpen on click only
unstyledbooleanDrop built-in classes
classstringMerged with the built-in classes
ui{ root?, list?, item?, link?, triggerIcon?, viewportWrapper?, viewport?, content?, panelLink?, panelLabel?, panelDescription?, panelIcon? }Per-slot class overrides

Slots

SlotPropsWhen to use it
listReplace the whole top-level list
trigger{ item }Render a panel trigger yourself
panel{ item }Replace a panel's contents entirely
item{ item }Render one top-level link yourself

Item shapes

ts
interface NavigationMenuLinkItem {
  label: string
  href?: string
  target?: string
  icon?: IconLike
  description?: string
  disabled?: boolean
  active?: boolean
  onSelect?: () => void
}

interface NavigationMenuGroupItem extends NavigationMenuLinkItem {
  items: NavigationMenuLinkItem[]
  columns?: 1 | 2 | 3
}

An entry without href renders a <button>, so onSelect can hand navigation to a router. active is reflected as both data-active and aria-current.