Navigation Menu
A collection of links for navigating websites.
Installation
npx shadcn@latest add @redpanda/navigation-menupnpm dlx shadcn@latest add @redpanda/navigation-menuyarn dlx shadcn@latest add @redpanda/navigation-menubunx shadcn@latest add @redpanda/navigation-menunubx shadcn@latest add @redpanda/navigation-menuaube dlx shadcn@latest add @redpanda/navigation-menuWhen to use
The Navigation Menu component provides structured navigation with dropdowns and nested content. Use this decision tree to determine when it’s appropriate:
Usage
import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuPositioner, NavigationMenuTrigger,} from '@/components/ui/navigation-menu';<NavigationMenu> <NavigationMenuList> <NavigationMenuItem> <NavigationMenuTrigger>Item One</NavigationMenuTrigger> <NavigationMenuContent> <NavigationMenuLink>Link</NavigationMenuLink> </NavigationMenuContent> </NavigationMenuItem> </NavigationMenuList></NavigationMenu>Examples
Link Component
Use variant="trigger" on a top-level navigation link to match adjacent menu triggers. The default variant is for links inside a menu popup. The render prop supports your router’s link component without changing its destination props.
import { NavigationMenuLink } from '@/components/ui/navigation-menu';<NavigationMenuItem> <NavigationMenuLink render={<Link href="/docs" />} variant="trigger"> Documentation </NavigationMenuLink></NavigationMenuItem>See also the Base UI documentation for handling client side routing.
Link recipes
Choose a complete link recipe rather than overriding its padding, gap, colors, or shape:
variant |
Purpose |
|---|---|
default |
Stacked title and description with an 8-pixel inset. |
trigger |
A top-level destination styled like the adjacent menu triggers. |
featured |
A promotional destination with a surface gradient and 24-pixel inset. |
icon |
A compact icon and label row with an 8-pixel gap. |
rich |
An icon alongside a title and description, with a 12-pixel gap. |
Native link destinations, refs, and the render integration remain available for every recipe.
Inline panel actions
Use NavigationMenuPanelButton for an action that changes the visible inline submenu, not for a destination. It is a native, non-submitting button composed with the registry Button. direction="forward" shows a trailing chevron and fills the row; direction="back" shows a leading chevron. Pass the panel-change callback through onClick.
Panel state and focus restoration belong to the composition: focus Back after entering a panel, then restore the originating action when returning. The inline submenu example below implements both transitions, including keyboard activation. Use NavigationMenuLink for actual navigation.
Popup dimensions and anchoring follow Base UI’s measured values immediately. Entrance opacity/scale and directional content transitions remain; changing panel dimensions no longer interpolates layout properties.
Panel dropdowns
Multi-level nested
Inline submenus
Large scrollable panel
Custom link component
Rich content mega-menu
Featured card
Vertical orientation
Props
Keyboard interactions
| Key | Action |
|---|---|
Tab into NavigationMenuList |
Focus lands on the first top-level trigger. |
ArrowLeft / ArrowRight |
Moves between top-level triggers. |
ArrowDown / Enter / Space |
Opens the focused trigger’s content panel and moves focus inside. |
Tab inside a content panel |
Cycles focus through the panel’s links. |
Escape |
Closes the open panel and restores focus to the trigger. |
Accessibility
- The menu container is
role="menubar"(ornavigationsemantics when used as site nav). Use a real<nav>wrapper and give it anaria-labelwhen there are multiple navigation regions on the page. - Links inside panels must be real
<a>elements — pass a framework-router link via therenderprop onNavigationMenuLinkso keyboard activation and focus handling still work. - Always provide a keyboard-accessible hamburger / skip-link on small screens; the navigation menu primitive is desktop-first.