Navigation Menu
A collection of links and menus for website navigation.
Anatomy
Import the component and assemble its parts:
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.
Custom links
The <NavigationMenu.Link> part can be customized to render the link from your framework using the render prop to enable client-side routing.
Large menus
When you have large menu content that doesn't fit in the viewport in some cases, you usually have two choices:
- 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.
- Make the navigation menu scrollable
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:valueto share it with the parent. A value passed withoutbind:holds until the parent changes it.- Type
Value | null- Default
null- Binding
bind:value
onValueChange function —
- Name
- Description
Called before the value changes. Call
eventDetails.cancel()to veto it.- Type
(value: Value | null, eventDetails: NavigationMenuChangeEventDetails) => void
onOpenChangeComplete function —
- Name
- 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
- Name
- Description
How long to wait before closing the navigation popup, in milliseconds.
- Type
number- Default
50
orientation NavigationMenuOrientation 'horizontal'
- Name
- 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
- Name
- Description
Whether the trigger ignores user interaction.
- Type
boolean | null- Default
false
nativeButton boolean true
- Name
- Description
Whether the host is a native
<button>. Setfalsewhenrendersupplies 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
data-pressed
data-disabled
Icon
An icon that shows the trigger opens a menu. Renders a <span> element.
children Snippet —
- Name
- 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
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
- Name
- 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
data-closed
data-activation-direction
data-starting-style
data-ending-style
Link
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
- Name
- 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
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
data-closed
data-starting-style
data-ending-style
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
- Name
- Description
Keep the portal mounted while the popup is closed.
- Type
boolean- Default
false
container HTMLElement | ShadowRoot | null —
- Name
- Description
Element the portal is appended to.
undefineduses the parent portal ordocument.body.nullwaits 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'
- Name
- Description
Determines which CSS
positionproperty 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
- Name
- 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
dataobject parameter with the following properties: -data.anchor: the dimensions of the anchor element with propertieswidthandheight. -data.positioner: the dimensions of the positioner element with propertieswidthandheight. -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
- Name
- 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
dataobject parameter with the following properties: -data.anchor: the dimensions of the anchor element with propertieswidthandheight. -data.positioner: the dimensions of the positioner element with propertieswidthandheight. -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'
- Name
- Description
An element or a rectangle that delimits the area that the popup is confined to.
- Type
Boundary- Default
'clipping-ancestors'
collisionPadding Padding 5
- Name
- Description
Additional space to maintain from the edge of the collision boundary.
- Type
Padding- Default
5
arrowPadding number 5
- Name
- 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 —
- Name
- Description
Determines how to handle collisions when positioning the popup.
sidecontrols overflow on the preferred placement axis (top/bottomorleft/right): -'flip': keep the requested side when it fits; otherwise try the opposite side (topandbottom, orleftandright). -'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.aligncontrols overflow on the alignment axis (start/center/end): -'flip': keep side, but swapstartandendwhen 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.fallbackAxisSidecontrols fallback behavior on the perpendicular axis when the preferred axis cannot fit: -'start': allow perpendicular fallback and try the logical start side first (topbeforebottom, orleftbeforerightin LTR). -'end': allow perpendicular fallback and try the logical end side first (bottombeforetop, orrightbeforeleftin LTR). -'none': do not fallback to the perpendicular axis.When
sideis'shift', explicitly settingalignonly supports'shift'or'none'. Ifalignis 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
data-closed
data-anchor-hidden
data-align
data-instant
data-side
--anchor-height
--anchor-width
--available-height
--available-width
--positioner-height
--positioner-width
--transform-origin
Popup
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
data-closed
data-anchor-hidden
data-align
data-side
data-starting-style
data-ending-style
--popup-height
--popup-width
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