Navigation Menu
A collection of links for navigating websites. The navigation menu provides a container for linking to different sections or pages, with support for nested popups and smooth sizing transitions.
import * as React from 'react'; import { NavigationMenu } from 'gnome-ui/navigation-menu'; import { ChevronDown, Box, Layout, Code, Settings } from 'lucide-react'; export function NavigationDefault() { return ( <NavigationMenu.Root className="relative z-10 flex w-full justify-center" delay={0} closeDelay={80}> <NavigationMenu.List className="flex items-center justify-center gap-1 rounded-xl border border-border bg-card p-1.5 shadow-sm"> <NavigationMenu.Item> <NavigationMenu.Trigger className="group flex items-center gap-1.5 rounded-xl px-3 py-2 text-sm font-medium text-foreground transition-colors duration-150 hover:bg-accent hover:text-accent-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring data-[popup-open]:bg-accent/60"> Products <NavigationMenu.Icon className="transition-transform duration-180 ease-out group-data-[popup-open]:rotate-180"> <Icons.ChevronDown className="size-4 text-muted-foreground" /> </NavigationMenu.Icon> </NavigationMenu.Trigger> <NavigationMenu.Content className="w-full p-4 transition-[opacity,transform] duration-180 ease-out data-[starting-style]:translate-y-1 data-[starting-style]:opacity-0 data-[ending-style]:-translate-y-1 data-[ending-style]:opacity-0 motion-reduce:transition-none md:w-[400px]"> <div className="grid grid-cols-2 gap-3"> <a href="#" className="flex flex-col gap-1.5 rounded-md p-3 transition-colors hover:bg-secondary"> <div className="flex items-center gap-2 text-sm font-semibold text-foreground"> <Icons.Box className="size-4 text-primary" /> Components </div> <p className="text-xs text-muted-foreground">Accessible building blocks for your UI.</p> </a> <a href="#" className="flex flex-col gap-1.5 rounded-md p-3 transition-colors hover:bg-secondary"> <div className="flex items-center gap-2 text-sm font-semibold text-foreground"> <Icons.Layout className="size-4 text-primary" /> Templates </div> <p className="text-xs text-muted-foreground">Pre-built layouts ready to integrate.</p> </a> </div> </NavigationMenu.Content> </NavigationMenu.Item> <NavigationMenu.Item> <NavigationMenu.Trigger className="group flex items-center gap-1.5 rounded-xl px-3 py-2 text-sm font-medium text-foreground transition-colors duration-150 hover:bg-accent hover:text-accent-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring data-[popup-open]:bg-accent/60"> Development <NavigationMenu.Icon className="transition-transform duration-180 ease-out group-data-[popup-open]:rotate-180"> <Icons.ChevronDown className="size-4 text-muted-foreground" /> </NavigationMenu.Icon> </NavigationMenu.Trigger> <NavigationMenu.Content className="w-full p-4 transition-[opacity,transform] duration-180 ease-out data-[starting-style]:translate-y-1 data-[starting-style]:opacity-0 data-[ending-style]:-translate-y-1 data-[ending-style]:opacity-0 motion-reduce:transition-none md:w-[250px]"> <div className="flex flex-col gap-2"> <a href="#" className="flex items-center gap-2 rounded-md p-2 text-sm font-medium text-foreground transition-colors hover:bg-secondary"> <Icons.Code className="size-4 text-muted-foreground" /> API Documentation </a> <a href="#" className="flex items-center gap-2 rounded-md p-2 text-sm font-medium text-foreground transition-colors hover:bg-secondary"> <Icons.Settings className="size-4 text-muted-foreground" /> Settings </a> </div> </NavigationMenu.Content> </NavigationMenu.Item> <NavigationMenu.Item> <NavigationMenu.Link href="#" className="block rounded-xl px-3 py-2 text-sm font-medium text-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"> Community </NavigationMenu.Link> </NavigationMenu.Item> </NavigationMenu.List> <NavigationMenu.Portal keepMounted> <NavigationMenu.Positioner className="z-50 pt-2" sideOffset={8}> <NavigationMenu.Popup className="origin-[var(--transform-origin)] rounded-xl border border-border bg-popover text-popover-foreground shadow-lg outline-none transition-[opacity,transform] duration-180 ease-out data-[starting-style]:translate-y-1 data-[starting-style]:opacity-0 data-[ending-style]:translate-y-1 data-[ending-style]:opacity-0 motion-reduce:transition-none"> <NavigationMenu.Arrow className="fill-border" /> <NavigationMenu.Viewport className="relative overflow-hidden rounded-xl bg-popover transition-[width,height] duration-180 ease-out motion-reduce:transition-none" /> </NavigationMenu.Popup> </NavigationMenu.Positioner> </NavigationMenu.Portal> </NavigationMenu.Root> ); }
Anatomy
import { NavigationMenu } from 'gnome-ui/navigation-menu'; <NavigationMenu.Root> <NavigationMenu.List> <NavigationMenu.Item> {/* Option 1: Element with submenu (Popup) */} <NavigationMenu.Trigger> <NavigationMenu.Icon /> </NavigationMenu.Trigger> <NavigationMenu.Content /> {/* Option 2: Direct link */} <NavigationMenu.Link /> </NavigationMenu.Item> </NavigationMenu.List> {/* Portal that manages the Popup placement */} <NavigationMenu.Portal> <NavigationMenu.Positioner> <NavigationMenu.Popup> <NavigationMenu.Arrow /> <NavigationMenu.Viewport /> </NavigationMenu.Popup> </NavigationMenu.Positioner> </NavigationMenu.Portal> </NavigationMenu.Root>
API reference
Root
Groups all parts of the navigation menu.
Renders a <nav> element at the root, or <div> element when nested.
Root Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| defaultValue | any | null | The uncontrolled value of the item that should be initially selected.To render a controlled navigation menu, use the value prop instead. |
| value | any | null | The controlled value of the navigation menu item that should be currently open.
When non-nullish, the menu will be open. When nullish, the menu will be closed.To render an uncontrolled navigation menu, use the defaultValue prop instead. |
| onValueChange | ((value: any, eventDetails: NavigationMenu.Root.ChangeEventDetails) => void) | - | Callback fired when the value changes. |
| actionsRef | RefObject<NavigationMenu.Root.Actions | null> | - | A ref to imperative actions. |
| onOpenChangeComplete | ((open: boolean) => void) | - | Event handler called after any animations complete when the navigation menu is closed. |
| delay | number | 50 | How long to wait before opening the navigation menu. Specified in milliseconds. |
| closeDelay | number | 50 | How long to wait before closing the navigation menu. Specified in milliseconds. |
| orientation | 'horizontal' | 'vertical' | 'horizontal' | The orientation of the navigation menu. |
| className | string | ((state: NavigationMenu.Root.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: NavigationMenu.Root.State) => CSSProperties | undefined) | - | - |
| render | ReactElement | ((props: HTMLProps, state: NavigationMenu.Root.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
List
Contains a list of navigation menu items.
Renders a <ul> element.
List Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | ((state: NavigationMenu.List.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: NavigationMenu.List.State) => CSSProperties | undefined) | - | - |
| render | ReactElement | ((props: HTMLProps, state: NavigationMenu.List.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Item
An individual navigation menu item.
Renders a <li> element.
Item Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| value | any | - | A unique value that identifies this navigation menu item. If no value is provided, a unique ID will be generated automatically. Use when controlling the navigation menu programmatically. |
| className | string | ((state: NavigationMenu.Item.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: NavigationMenu.Item.State) => CSSProperties | undefined) | - | - |
| render | ReactElement | ((props: HTMLProps, state: NavigationMenu.Item.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Trigger
Opens the navigation menu popup when hovered or clicked, revealing the
associated content.
Renders a <button> element.
Trigger Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| nativeButton | boolean | true | Whether the component renders a native <button> element when replacing it
via the render prop.
Set to false if the rendered element is not a button (e.g. <div>). |
| className | string | ((state: NavigationMenu.Trigger.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: NavigationMenu.Trigger.State) => CSSProperties | undefined) | - | - |
| render | ReactElement | ((props: HTMLProps, state: NavigationMenu.Trigger.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Trigger Data Attributes:
| Attribute | Type | Description |
|---|---|---|
| data-popup-open | - | Present when the corresponding navigation menu is open. |
| data-pressed | - | Present when the trigger is pressed. |
Icon
An icon that indicates that the trigger button opens a menu.
Icon Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | ((state: NavigationMenu.Icon.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: NavigationMenu.Icon.State) => CSSProperties | undefined) | - | - |
| render | ReactElement | ((props: HTMLProps, state: NavigationMenu.Icon.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Content
A container for the content of the navigation menu item that is moved into the popup
when the item is active.
Renders a <div> element.
Content Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | ((state: NavigationMenu.Content.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: NavigationMenu.Content.State) => CSSProperties | undefined) | - | - |
| keepMounted | boolean | false | Whether to keep the content mounted in the DOM while the popup is closed. Ensures the content is present during server-side rendering for web crawlers. |
| render | ReactElement | ((props: HTMLProps, state: NavigationMenu.Content.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Content Data Attributes:
| Attribute | Type | Description |
|---|---|---|
| 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 is animating in. |
| data-ending-style | - | Present when the content is animating out. |
Link
A link in the navigation menu that can be used to navigate to a different page or section.
Renders an <a> element.
Link Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| closeOnClick | boolean | false | Whether to close the navigation menu when the link is clicked. |
| active | boolean | false | Whether the link is the currently active page. |
| className | string | ((state: NavigationMenu.Link.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: NavigationMenu.Link.State) => CSSProperties | undefined) | - | - |
| render | ReactElement | ((props: HTMLProps, state: NavigationMenu.Link.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Link Data Attributes:
| Attribute | Type | Description |
|---|---|---|
| data-active | - | Present when the link is the currently active page. |
Backdrop
A backdrop for the navigation menu popup.
Renders a <div> element.
Backdrop Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | ((state: NavigationMenu.Backdrop.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: NavigationMenu.Backdrop.State) => CSSProperties | undefined) | - | - |
| render | ReactElement | ((props: HTMLProps, state: NavigationMenu.Backdrop.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Backdrop Data Attributes:
| Attribute | Type | Description |
|---|---|---|
| data-open | - | Present when the popup is open. |
| data-closed | - | Present when the popup is closed. |
| data-starting-style | - | Present when the popup is 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>.
Renders a <div> element.
Portal Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| container | HTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | null | - | A parent element to render the portal element into. |
| className | string | ((state: NavigationMenu.Portal.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: NavigationMenu.Portal.State) => CSSProperties | undefined) | - | - |
| keepMounted | boolean | false | Whether to keep the portal mounted in the DOM while the popup is hidden. |
| render | ReactElement | ((props: HTMLProps, state: NavigationMenu.Portal.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Positioner
Positions the navigation menu against the currently active trigger.
Renders a <div> element.
Positioner Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| disableAnchorTracking | boolean | false | Whether to disable the popup from tracking any layout shift of its positioning anchor. |
| align | Align | 'center' | How to align the popup relative to the specified side. |
| alignOffset | number | OffsetFunction | 0 | 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 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. | | side |Side|'bottom'| Which side of the anchor element to align the popup against. May automatically change to avoid collisions. | | sideOffset |number \| OffsetFunction|0| 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 adataobject 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. | | arrowPadding |number|5| 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. | | anchor |Element \| VirtualElement \| RefObject<Element \| null> \| (() => Element \| VirtualElement \| null) \| null| - | An element to position the popup against. By default, the popup will be positioned against the trigger. | | collisionAvoidance |CollisionAvoidance| - | Determines how to handle collisions when positioning the popup. | | collisionBoundary |Boundary|'clipping-ancestors'| An element or a rectangle that delimits the area that the popup is confined to. | | collisionPadding |Padding|5| Additional space to maintain from the edge of the collision boundary. | | sticky |boolean|false| Whether to maintain the popup in the viewport after the anchor element was scrolled out of view. | | positionMethod |'absolute' \| 'fixed'|'absolute'| Determines which CSSpositionproperty to use. | | className |string \| ((state: NavigationMenu.Positioner.State) => string \| undefined)| - | CSS class applied to the element, or a function that returns a class based on the component’s state. | | style |CSSProperties \| ((state: NavigationMenu.Positioner.State) => CSSProperties \| undefined)| - | - | | render |ReactElement \| ((props: HTMLProps, state: NavigationMenu.Positioner.State) => ReactElement)| - | Allows you to replace the component’s HTML element with a different tag, or compose it with another component.Accepts aReactElementor a function that returns the element to render. |
Positioner Data Attributes:
| Attribute | Type | Description |
|---|---|---|
| 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 | 'start' | 'center' | 'end' | Indicates how the popup is aligned relative to the specified side. |
| data-instant | - | Present if animations should be instant. |
| data-side | 'top' | 'bottom' | 'left' | 'right' | 'inline-end' | 'inline-start' | Indicates which side the popup is positioned relative to the trigger. |
Positioner CSS Variables:
| Variable | Type | Default | Description |
|---|---|---|---|
| --anchor-height | number | - | The anchor's height. |
| --anchor-width | number | - | The anchor's width. |
| --available-height | number | - | The available height between the trigger and the edge of the viewport. |
| --available-width | number | - | The available width between the trigger and the edge of the viewport. |
| --positioner-height | number | - | The fixed height of the positioner element. |
| --positioner-width | number | - | The fixed width of the positioner element. |
| --transform-origin | string | - | The coordinates that this element is anchored to. Used for animations and transitions. |
Popup
A container for the navigation menu contents.
Renders a <nav> element.
Popup Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | ((state: NavigationMenu.Popup.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: NavigationMenu.Popup.State) => CSSProperties | undefined) | - | - |
| render | ReactElement | ((props: HTMLProps, state: NavigationMenu.Popup.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Popup Data Attributes:
| Attribute | Type | Description |
|---|---|---|
| data-open | - | Present when the popup is open. |
| data-closed | - | Present when the popup is closed. |
| data-align | 'start' | 'center' | 'end' | Indicates how the popup is aligned relative to the specified side. |
| data-side | 'top' | 'bottom' | 'left' | 'right' | 'inline-end' | 'inline-start' | Indicates which side the popup is positioned relative to the trigger. |
| data-starting-style | - | Present when the popup is animating in. |
| data-ending-style | - | Present when the popup is animating out. |
Popup CSS Variables:
| Variable | Type | Default | Description |
|---|---|---|---|
| --popup-height | number | - | The fixed height of the popup element. |
| --popup-width | number | - | The fixed width of the popup element. |
Viewport
The clipping viewport of the navigation menu's current content.
Renders a <div> element.
Viewport Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | ((state: NavigationMenu.Viewport.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: NavigationMenu.Viewport.State) => CSSProperties | undefined) | - | - |
| render | ReactElement | ((props: HTMLProps, state: NavigationMenu.Viewport.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Arrow
Displays an element pointing toward the navigation menu's current anchor.
Renders a <div> element.
Arrow Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | ((state: NavigationMenu.Arrow.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: NavigationMenu.Arrow.State) => CSSProperties | undefined) | - | - |
| render | ReactElement | ((props: HTMLProps, state: NavigationMenu.Arrow.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Arrow Data Attributes:
| Attribute | Type | Description |
|---|---|---|
| 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 | 'start' | 'center' | 'end' | Indicates how the popup is aligned relative to specified side. |
| data-side | 'top' | 'bottom' | 'left' | 'right' | 'inline-end' | 'inline-start' | Indicates which side the popup is positioned relative to the trigger. |