Skip to contents

Navigation Menu

A collection of links and menus for website navigation.

Anatomy

Import the component and assemble its parts:

Anatomy

Examples

Nested submenus

<NavigationMenu.Root> component can be nested within a higher-level <NavigationMenu.Content> part to create a multi-level navigation menu.

Nested inline submenus

For second-level navigation that should stay in the same panel, omit the nested <NavigationMenu.Portal> and render only List + Viewport with an initial value.

The <NavigationMenu.Link> part can be customized to render the link from your framework using the render prop to enable client-side routing.

Custom link component example

Large menus

When you have large menu content that doesn't fit in the viewport in some cases, you usually have two choices:

  1. Compress the navigation menu content

You can change the layout of the navigation menu to render less content or be more compact by reducing the space it takes up. If your content is flexible, you can use the max-height property on .Popup to limit the height of the navigation menu to let it compress itself while preventing overflow.

Compact layout
  1. Make the navigation menu scrollable
Scrollable layout

Native scrollbars are visible while transitioning content, so we recommend using the Scroll Area component instead of native scrollbars to keep them hidden, which also allows the Arrow to be centered correctly.

Closing animations

The popup stays rendered until its closing animation finishes. See JavaScript animations and Manual unmounting for animating it in JavaScript and for manual control. For Navigation Menu, call eventDetails.preventUnmountOnClose() in onValueChange when the value becomes null, and call close() on the root (bound with bind:this) instead of setting value to null directly.

API reference

Root

Groups all parts of the navigation menu. Renders a <nav> element, or a <div> when nested.

value Value | null null
Name
Description

The value of the item whose content is open. A nullish value closes the menu. Use bind:value to share it with the parent. A value passed without bind: holds until the parent changes it.

Type
Value | null
Default
null
Binding
bind:value
onValueChange function —
Description

Called before the value changes. Call eventDetails.cancel() to veto it.

Type
(value: Value | null, eventDetails: NavigationMenuChangeEventDetails) => void
onOpenChangeComplete function —
Description

Called after any animations complete when the navigation menu is closed.

Type
(open: boolean) => void
delay number 50
Name
Description

How long to wait before opening the navigation popup, in milliseconds.

Type
number
Default
50
closeDelay number 50
Description

How long to wait before closing the navigation popup, in milliseconds.

Type
number
Default
50
orientation NavigationMenuOrientation 'horizontal'
Description

The orientation of the navigation menu.

Type
NavigationMenuOrientation
Default
'horizontal'
render Snippet<[props: HTMLAttributes<HTMLElement>, state: NavigationMenuRootState, children: Snippet | undefined]> —
Name
Description

Replace the <nav> element, or the <div> of a nested root.

Type
Snippet<[props: HTMLAttributes<HTMLElement>, state: NavigationMenuRootState, children: Snippet | undefined]>
open boolean
Name
open
Description

Whether the popup is open.

Type
boolean
nested boolean
Name
nested
Description

Whether the navigation menu is nested in another one.

Type
boolean

List

Contains a list of navigation menu items. Renders a <ul> element.

render Snippet<[props: HTMLAttributes<HTMLUListElement>, state: NavigationMenuListState, children: Snippet | undefined]> —
Name
Type
Snippet<[props: HTMLAttributes<HTMLUListElement>, state: NavigationMenuListState, children: Snippet | undefined]>
open boolean
Name
open
Description

Whether the popup is open.

Type
boolean

Item

An individual navigation menu item. Renders an <li> element.

value unknown —
Name
Description

A unique value that identifies this item. An id is generated when no value is passed. Use it when controlling the navigation menu programmatically.

Type
unknown
render Snippet<[props: HTMLAttributes<HTMLLIElement>, state: NavigationMenuItemState, children: Snippet | undefined]> —
Name
Type
Snippet<[props: HTMLAttributes<HTMLLIElement>, state: NavigationMenuItemState, children: Snippet | undefined]>

Trigger

Opens the navigation menu popup when hovered or clicked, revealing the associated content. Renders a <button> element.

disabled boolean | null false
Description

Whether the trigger ignores user interaction.

Type
boolean | null
Default
false
nativeButton boolean true
Description

Whether the host is a native <button>. Set false when render supplies a non-button element.

Type
boolean
Default
true
render Snippet<[props: NavigationMenuTriggerHostProps, state: NavigationMenuTriggerState, children: Snippet | undefined]> —
Name
Type
Snippet<[props: NavigationMenuTriggerHostProps, state: NavigationMenuTriggerState, children: Snippet | undefined]>
open boolean
Name
open
Description

Whether the popup is open and this item is active.

Type
boolean
disabled boolean
Name
disabled
Description

Whether the trigger ignores user interaction.

Type
boolean
data-popup-open
Present when the corresponding navigation menu is open.
data-pressed
Present when the trigger is pressed.
data-disabled
Present when the trigger is disabled.

Icon

An icon that shows the trigger opens a menu. Renders a <span> element.

children Snippet —
Description

Replaces the default ▼ glyph.

Type
Snippet
render Snippet<[props: HTMLAttributes<HTMLSpanElement>, state: NavigationMenuIconState, children: Snippet | undefined]> —
Name
Type
Snippet<[props: HTMLAttributes<HTMLSpanElement>, state: NavigationMenuIconState, children: Snippet | undefined]>
open boolean
Name
open
Description

Whether the popup is open and this item is active.

Type
boolean
data-popup-open
Present when the navigation menu is open and the item is active.

Content

A container for the content of an item. It moves into the viewport while the item is active. Renders a <div> element.

keepMounted boolean false
Description

Whether to keep the content mounted while the popup is closed. The content is then present in server-rendered HTML for crawlers.

Type
boolean
Default
false
render Snippet<[props: HTMLAttributes<HTMLDivElement>, state: NavigationMenuContentState, children: Snippet | undefined]> —
Name
Type
Snippet<[props: HTMLAttributes<HTMLDivElement>, state: NavigationMenuContentState, children: Snippet | undefined]>
open boolean
Name
open
Description

Whether this content is the open one.

Type
boolean
transitionStatus 'starting' | 'ending' | 'idle' | undefined
Name
transitionStatus
Type
'starting' | 'ending' | 'idle' | undefined
activationDirection NavigationMenuActivationDirection
Name
activationDirection
Description

The direction the active trigger moved in when the content changed.

Type
NavigationMenuActivationDirection
data-open
Present when the popup is open.
data-closed
Present when the popup is closed.
data-activation-direction
Which direction another trigger was activated from.
data-starting-style
Present when the content begins animating in.
data-ending-style
Present when the content is animating out.

A link in the navigation menu. Renders an <a> element.

active boolean false
Name
Description

Whether the link is the current page.

Type
boolean
Default
false
closeOnClick boolean false
Description

Whether clicking the link closes the navigation menu.

Type
boolean
Default
false
render Snippet<[props: HTMLAnchorAttributes, state: NavigationMenuLinkState, children: Snippet | undefined]> —
Name
Type
Snippet<[props: HTMLAnchorAttributes, state: NavigationMenuLinkState, children: Snippet | undefined]>
active boolean
Name
active
Description

Whether the link is the current page.

Type
boolean
data-active
Present when the link is the currently active page.

Backdrop

A backdrop for the navigation menu popup. Renders a <div> element.

render Snippet<[props: HTMLAttributes<HTMLDivElement>, state: NavigationMenuBackdropState, children: Snippet | undefined]> —
Name
Type
Snippet<[props: HTMLAttributes<HTMLDivElement>, state: NavigationMenuBackdropState, children: Snippet | undefined]>
open boolean
Name
open
Type
boolean
transitionStatus 'starting' | 'ending' | 'idle' | undefined
Name
transitionStatus
Type
'starting' | 'ending' | 'idle' | undefined
data-open
Present when the popup is open.
data-closed
Present when the popup is closed.
data-starting-style
Present when the popup begins animating in.
data-ending-style
Present when the popup is animating out.

Portal

A portal element that moves the popup to a different part of the DOM. By default, the portal element is appended to <body>.

keepMounted boolean false
Description

Keep the portal mounted while the popup is closed.

Type
boolean
Default
false
container HTMLElement | ShadowRoot | null —
Description

Element the portal is appended to. undefined uses the parent portal or document.body. null waits and does not mount until an element or shadow root is set. There is no ref object.

Type
HTMLElement | ShadowRoot | null
render Snippet<[props: HTMLAttributes<HTMLDivElement> & Record<symbol, Attachment<HTMLDivElement>>, state: NavigationMenuPortalState, children: Snippet | undefined]> —
Name
Description

Replace the portal element. The snippet receives host props, an empty state, and the children snippet. Host props include the move attachment.

Type
Snippet<[props: HTMLAttributes<HTMLDivElement> & Record<symbol, Attachment<HTMLDivElement>>, state: NavigationMenuPortalState, children: Snippet | undefined]>

Positioner

Positions the navigation menu against the currently active trigger. Renders a <div> element.

anchor Anchor —
Name
Description

An element to position the popup against. By default, the popup will be positioned against the trigger.

Type
Anchor
positionMethod "absolute" | "fixed" 'absolute'
Description

Determines which CSS position property to use.

Type
"absolute" | "fixed"
Default
'absolute'
side Side 'bottom'
Name
Description

Which side of the anchor element to align the popup against. May automatically change to avoid collisions.

Type
Side
Default
'bottom'
align Align 'center'
Name
Description

How to align the popup relative to the specified side.

Type
Align
Default
'center'
sideOffset number | OffsetFunction 0
Description

Distance between the anchor and the popup in pixels. Also accepts a function that returns the distance to read the dimensions of the anchor and positioner elements, along with its side and alignment.

The function takes a data object parameter with the following properties: - data.anchor: the dimensions of the anchor element with properties width and height. - data.positioner: the dimensions of the positioner element with properties width and height. - data.side: which side of the anchor element the positioner is aligned against. - data.align: how the positioner is aligned relative to the specified side.

Type
number | OffsetFunction
Default
0
alignOffset number | OffsetFunction 0
Description

Additional offset along the alignment axis in pixels. Also accepts a function that returns the offset to read the dimensions of the anchor and positioner elements, along with its side and alignment.

The function takes a data object parameter with the following properties: - data.anchor: the dimensions of the anchor element with properties width and height. - data.positioner: the dimensions of the positioner element with properties width and height. - data.side: which side of the anchor element the positioner is aligned against. - data.align: how the positioner is aligned relative to the specified side.

Type
number | OffsetFunction
Default
0
collisionBoundary Boundary 'clipping-ancestors'
Description

An element or a rectangle that delimits the area that the popup is confined to.

Type
Boundary
Default
'clipping-ancestors'
collisionPadding Padding 5
Description

Additional space to maintain from the edge of the collision boundary.

Type
Padding
Default
5
arrowPadding number 5
Description

Minimum distance to maintain between the arrow and the edges of the popup.

Use it to prevent the arrow element from hanging out of the rounded corners of a popup.

Type
number
Default
5
sticky boolean false
Name
Description

Whether to maintain the popup in the viewport after the anchor element was scrolled out of view.

Type
boolean
Default
false
disableAnchorTracking boolean false
Description

Whether to disable the popup from tracking any layout shift of its positioning anchor.

Type
boolean
Default
false
collisionAvoidance CollisionAvoidance —
Description

Determines how to handle collisions when positioning the popup.

side controls overflow on the preferred placement axis (top/bottom or left/right): - 'flip': keep the requested side when it fits; otherwise try the opposite side (top and bottom, or left and right). - 'shift': never change side; keep the requested side and move the popup within the clipping boundary so it stays visible. - 'none': do not correct side-axis overflow.

align controls overflow on the alignment axis (start/center/end): - 'flip': keep side, but swap start and end when the requested alignment overflows. - 'shift': keep side and requested alignment, then nudge the popup along the alignment axis to fit. - 'none': do not correct alignment-axis overflow.

fallbackAxisSide controls fallback behavior on the perpendicular axis when the preferred axis cannot fit: - 'start': allow perpendicular fallback and try the logical start side first (top before bottom, or left before right in LTR). - 'end': allow perpendicular fallback and try the logical end side first (bottom before top, or right before left in LTR). - 'none': do not fallback to the perpendicular axis.

When side is 'shift', explicitly setting align only supports 'shift' or 'none'. If align is omitted, it defaults to 'flip'.

Type
CollisionAvoidance
render Snippet<[props: HTMLAttributes<HTMLDivElement>, state: NavigationMenuPositionerState, children: Snippet | undefined]> —
Name
Type
Snippet<[props: HTMLAttributes<HTMLDivElement>, state: NavigationMenuPositionerState, children: Snippet | undefined]>
open boolean
Name
open
Type
boolean
side Side
Name
side
Type
Side
align Align
Name
align
Type
Align
anchorHidden boolean
Name
anchorHidden
Type
boolean
instant boolean
Name
instant
Description

Whether CSS transitions should be disabled.

Type
boolean
data-open
Present when the popup is open.
data-closed
Present when the popup is closed.
data-anchor-hidden
Present when the anchor is hidden.
data-align
Indicates how the popup is aligned relative to the specified side.
data-instant
Present if animations should be instant.
data-side
Indicates which side the popup is positioned relative to the trigger.
--anchor-height
The anchor's height.
--anchor-width
The anchor's width.
--available-height
The available height between the trigger and the edge of the viewport.
--available-width
The available width between the trigger and the edge of the viewport.
--positioner-height
The fixed height of the positioner element.
--positioner-width
The fixed width of the positioner element.
--transform-origin
The coordinates that this element is anchored to. Used for animations and transitions.

A container for the navigation menu contents. Renders a <nav> element.

render Snippet<[props: HTMLAttributes<HTMLElement>, state: NavigationMenuPopupState, children: Snippet | undefined]> —
Name
Type
Snippet<[props: HTMLAttributes<HTMLElement>, state: NavigationMenuPopupState, children: Snippet | undefined]>
open boolean
Name
open
Type
boolean
transitionStatus 'starting' | 'ending' | 'idle' | undefined
Name
transitionStatus
Type
'starting' | 'ending' | 'idle' | undefined
side Side
Name
side
Type
Side
align Align
Name
align
Type
Align
anchorHidden boolean
Name
anchorHidden
Type
boolean
data-open
Present when the popup is open.
data-closed
Present when the popup is closed.
data-anchor-hidden
Present when the anchor is hidden.
data-align
Indicates how the popup is aligned relative to the specified side.
data-side
Indicates which side the popup is positioned relative to the trigger.
data-starting-style
Present when the popup begins animating in.
data-ending-style
Present when the popup is animating out.
--popup-height
The fixed height of the popup element.
--popup-width
The fixed width of the popup element.

Viewport

The clipping viewport of the navigation menu's current content. Renders a <div> element.

render Snippet<[props: HTMLAttributes<HTMLDivElement>, state: NavigationMenuViewportState, children: Snippet | undefined]> —
Name
Type
Snippet<[props: HTMLAttributes<HTMLDivElement>, state: NavigationMenuViewportState, children: Snippet | undefined]>

Arrow

Displays an element positioned against the navigation menu anchor. Renders a <div> element.

render Snippet<[props: HTMLAttributes<HTMLDivElement>, state: NavigationMenuArrowState, children: Snippet | undefined]> —
Name
Type
Snippet<[props: HTMLAttributes<HTMLDivElement>, state: NavigationMenuArrowState, children: Snippet | undefined]>
open boolean
Name
open
Type
boolean
side Side
Name
side
Type
Side
align Align
Name
align
Type
Align
uncentered boolean
Name
uncentered
Type
boolean
data-open
Present when the popup is open.
data-closed
Present when the popup is closed.
data-uncentered
Present when the popup arrow is uncentered.
data-align
Indicates how the popup is aligned relative to specified side.
data-side
Indicates which side the popup is positioned relative to the trigger.