Navigation Menu
A collection of links and panels for navigating a website, with keyboard support and an animated, resizing viewport.
Default
Each NavigationMenu.Item holds either a NavigationMenu.Trigger with its NavigationMenu.Content panel, or a single NavigationMenu.Link. Panels open on hover or click and share one viewport that resizes between them.
tsx
import { NavigationMenu } from "@hummingbirdui/react";
const components = ["Accordion", "Alert", "Button", "Card", "Dialog", "Tabs"];
export default function NavigationMenuDefault() {
return (
<NavigationMenu>
<NavigationMenu.List>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Getting started</NavigationMenu.Trigger>
<NavigationMenu.Content>
<ul className="w-56">
<li>
<NavigationMenu.Link href="#">Introduction</NavigationMenu.Link>
</li>
<li>
<NavigationMenu.Link href="#">Installation</NavigationMenu.Link>
</li>
<li>
<NavigationMenu.Link href="#">Dark mode</NavigationMenu.Link>
</li>
</ul>
</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Components</NavigationMenu.Trigger>
<NavigationMenu.Content>
<ul className="grid w-80 grid-cols-2">
{components.map((component) => (
<li key={component}>
<NavigationMenu.Link href="#">
{component}
</NavigationMenu.Link>
</li>
))}
</ul>
</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Link href="#">Blocks</NavigationMenu.Link>
</NavigationMenu.Item>
</NavigationMenu.List>
</NavigationMenu>
);
}With descriptions
A NavigationMenu.Link lays out its children in a column, so a title and a short description can sit inside one link.
tsx
import { NavigationMenu } from "@hummingbirdui/react";
const features = [
{
title: "Analytics",
description: "Track traffic, conversions and retention in real time.",
},
{
title: "Automation",
description: "Trigger workflows from events without writing code.",
},
{
title: "Integrations",
description: "Connect the tools your team already relies on.",
},
{
title: "Security",
description: "Single sign-on, audit logs and role-based access.",
},
];
export default function NavigationMenuDescriptions() {
return (
<NavigationMenu>
<NavigationMenu.List>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Product</NavigationMenu.Trigger>
<NavigationMenu.Content>
<ul className="grid w-96 grid-cols-2 gap-1">
{features.map((feature) => (
<li key={feature.title}>
<NavigationMenu.Link href="#">
<span className="font-medium">{feature.title}</span>
<span className="text-muted">{feature.description}</span>
</NavigationMenu.Link>
</li>
))}
</ul>
</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Link href="#">Pricing</NavigationMenu.Link>
</NavigationMenu.Item>
</NavigationMenu.List>
</NavigationMenu>
);
}Without viewport
Setting viewport={false} renders each panel below its own item with its own surface instead of inside the shared viewport.
tsx
import { NavigationMenu } from "@hummingbirdui/react";
const menus = [
{ title: "Solutions", links: ["Marketing", "Sales", "Support"] },
{ title: "Resources", links: ["Blog", "Guides", "Changelog"] },
];
export default function NavigationMenuNoViewport() {
return (
<NavigationMenu viewport={false}>
<NavigationMenu.List>
{menus.map((menu) => (
<NavigationMenu.Item key={menu.title}>
<NavigationMenu.Trigger>{menu.title}</NavigationMenu.Trigger>
<NavigationMenu.Content>
<ul className="w-48">
{menu.links.map((link) => (
<li key={link}>
<NavigationMenu.Link href="#">{link}</NavigationMenu.Link>
</li>
))}
</ul>
</NavigationMenu.Content>
</NavigationMenu.Item>
))}
</NavigationMenu.List>
</NavigationMenu>
);
}Active link
The active prop marks the link for the current page, both at the top level and inside a panel.
tsx
import { NavigationMenu } from "@hummingbirdui/react";
export default function NavigationMenuActive() {
return (
<NavigationMenu>
<NavigationMenu.List>
<NavigationMenu.Item>
<NavigationMenu.Link href="#" active>
Overview
</NavigationMenu.Link>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Settings</NavigationMenu.Trigger>
<NavigationMenu.Content>
<ul className="w-48">
<li>
<NavigationMenu.Link href="#">Profile</NavigationMenu.Link>
</li>
<li>
<NavigationMenu.Link href="#" active>
Billing
</NavigationMenu.Link>
</li>
<li>
<NavigationMenu.Link href="#">
Notifications
</NavigationMenu.Link>
</li>
</ul>
</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Link href="#">Reports</NavigationMenu.Link>
</NavigationMenu.Item>
</NavigationMenu.List>
</NavigationMenu>
);
}Indicator
NavigationMenu.Indicator renders an arrow below the trigger of the open panel.
tsx
import { NavigationMenu } from "@hummingbirdui/react";
const menus = [
{ title: "Products", links: ["Analytics", "Automation", "Reports"] },
{ title: "Company", links: ["About", "Careers", "Press"] },
];
export default function NavigationMenuIndicator() {
return (
<NavigationMenu>
<NavigationMenu.List>
{menus.map((menu) => (
<NavigationMenu.Item key={menu.title}>
<NavigationMenu.Trigger>{menu.title}</NavigationMenu.Trigger>
<NavigationMenu.Content>
<ul className="w-48">
{menu.links.map((link) => (
<li key={link}>
<NavigationMenu.Link href="#">{link}</NavigationMenu.Link>
</li>
))}
</ul>
</NavigationMenu.Content>
</NavigationMenu.Item>
))}
<NavigationMenu.Indicator />
</NavigationMenu.List>
</NavigationMenu>
);
}API Reference
Built on the Radix UI Navigation Menu primitive. Each part forwards all props to its Radix counterpart.
NavigationMenu
Contains all the parts of a navigation menu.
| Prop | Type | Default |
|---|---|---|
defaultValue | string | — |
value | string | — |
onValueChange | function | — |
delayDuration | number | 200 |
skipDelayDuration | number | 300 |
dir | enum | — |
orientation | enum | "horizontal" |
viewport | boolean | true |
className | string | — |
| Data attribute | Values |
|---|---|
[data-orientation] | "vertical" | "horizontal" |
[data-viewport] | "true" | "false" |
NavigationMenu.List
Contains the top level menu items.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
className | string | — |
| Data attribute | Values |
|---|---|
[data-orientation] | "vertical" | "horizontal" |
NavigationMenu.Item
A top level menu item, containing a link or a trigger with its content.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
value | string | — |
className | string | — |
NavigationMenu.Trigger
The button that toggles a panel. It renders a trailing chevron that flips while the panel is open.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
className | string | — |
| Data attribute | Values |
|---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
NavigationMenu.Content
The panel associated with a trigger.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
onEscapeKeyDown | function | — |
onPointerDownOutside | function | — |
onFocusOutside | function | — |
onInteractOutside | function | — |
forceMount | boolean | — |
className | string | — |
| Data attribute | Values |
|---|---|
[data-state] | "open" | "closed" |
[data-motion] | "to-start" | "to-end" | "from-start" | "from-end" |
[data-orientation] | "vertical" | "horizontal" |
NavigationMenu.Link
A navigational link. Inside a panel it renders as a menu row; placed directly in an item it matches the triggers.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
active | boolean | false |
onSelect | function | — |
className | string | — |
| Data attribute | Values |
|---|---|
[data-active] | Present when active |
NavigationMenu.Indicator
An optional arrow rendered below the list to highlight the open trigger.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
forceMount | boolean | — |
className | string | — |
| Data attribute | Values |
|---|---|
[data-state] | "visible" | "hidden" |
[data-orientation] | "vertical" | "horizontal" |
NavigationMenu.Viewport
The surface that renders the open panel. NavigationMenu adds it automatically unless viewport={false} is set.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
forceMount | boolean | — |
className | string | — |
| Data attribute | Values |
|---|---|
[data-state] | "open" | "closed" |
[data-orientation] | "vertical" | "horizontal" |
| CSS Variable | Description |
|---|---|
--radix-navigation-menu-viewport-width | The width of the viewport when visible/hidden, computed from the active content. |
--radix-navigation-menu-viewport-height | The height of the viewport when visible/hidden, computed from the active content. |
Styling
Hummingbird React navigation menu is styled through Hummingbird's utility classes and CSS variables. Triggers and top-level links reuse the nav-link class, and panels reuse the dropdown's surface tokens.
- The
navigation-menu,navigation-menu-list,navigation-menu-item,navigation-menu-trigger,navigation-menu-content,navigation-menu-viewport,navigation-menu-linkandnavigation-menu-indicatorclasses ship with@hummingbirdui/react. - The
navigation-menuclass defines the--nav-link-*variables for its triggers and the--navigation-menu-*variables (surface, spacing and link colors) for its panels. - See the Nav CSS Variables and Dropdown CSS Variables documentation for the underlying tokens.