Navigation Menu
A Navigation Menu allows users to reach the main links of a site, with panels of more links that open below a trigger.
When to Use
- for the main links in the header of a site, such as “Product”, “Pricing”, and “Help”
- for a section whose pages each need a line of description, in a panel below a trigger, such as “Invoices”, “Time”, and “Estimates” under “Product”
When Not to Use
- for the sections of an app (use a Sidebar)
- for commands, as a Navigation Menu contains links and sets no
menurole (use a Menubar or a Dropdown Menu) - for views that switch in place (use Tabs)
- for the path to the current page (use a Breadcrumb)
See Dropdown Menu for a comparison of the four menus.
Anatomy
| Element | Usage |
|---|---|
| Trigger | Optional |
| Caret | On every trigger |
| Link | Optional |
The figure shows the row. The panel of a trigger opens in a popup below it and contains NavigationMenuLink parts in any layout. NavigationMenu renders the portal, the positioner, and the popup after its children, and NavigationMenuTrigger adds the caret.
States
A disabled trigger stays closed.
Behavior
A Navigation Menu isn’t modal: the page can still scroll while a panel is open.
A trigger and a link styled with navigationMenuTriggerStyle() are 36px tall, which is the height of an lg Button. If a Button is in the same row, set size="lg" on it.
By default, the popup is aligned with the start edge of its trigger. To center it or to align the end edges, set align on NavigationMenu. The popup is as wide and as tall as the panel, which adds no layout. If the window is too narrow for the popup, it moves sideways to stay inside the window.
Accessibility
Base UI’s Navigation Menu renders a nav that contains a list of buttons and links. It sets no menu role, so the parts keep the roles of their elements.
Keyboard
| Key | Result |
|---|---|
Tab | Moves focus to each trigger and link in the row. From an open trigger, focus enters the panel first. |
ArrowRight, ArrowLeft | Moves focus to the next or the previous trigger or link in the row. Focus stops at the first and last. |
Enter or Space on a trigger | Opens or closes its panel. Focus stays on the trigger. |
ArrowDown on a trigger | Opens its panel. Focus stays on the trigger. |
ArrowDown, ArrowUp in a panel | Moves focus to the next or the previous link. From the last link, focus moves to the first. |
Enter on a link | Follows the link. An open panel stays open. |
Escape | Closes the panel. Focus returns to its trigger. |
Requirements
Set active on the link to the current page. The link then has aria-current="page".
If the page has another nav, such as a Breadcrumb, set an aria-label on NavigationMenu, for example “Main”. If the two landmarks have no names, screen reader users can’t tell them apart.
Installation
npx shadcn@latest add @summit/navigation-menuUsage
You provide the layout of each panel. To style a link in the row like a trigger, pass navigationMenuTriggerStyle() to its className.
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle,
} from '@/components/ui/navigation-menu';
<NavigationMenu aria-label="Main">
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Product</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-72 gap-1">
<li>
<NavigationMenuLink href="/invoices" className="flex-col items-start gap-1">
<span className="font-medium">Invoices</span>
<span className="text-muted-foreground">Bill clients and get paid online.</span>
</NavigationMenuLink>
</li>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="/pricing" className={navigationMenuTriggerStyle()}>
Pricing
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>;With a Router Link
To use a router’s link, pass it through render, and set active from the current path. By default, a click on a link in a panel doesn’t close the panel. If a NavigationMenuLink changes the page without a reload, set closeOnClick on it.
import Link from 'next/link';
import { usePathname } from 'next/navigation';
const pathname = usePathname();
<NavigationMenuLink render={<Link href="/pricing" />} active={pathname === '/pricing'} closeOnClick>
Pricing
</NavigationMenuLink>;API Reference
The parts accept the props of their matching parts in Base UI’s Navigation Menu. See the Base UI Navigation Menu documentation for value, onValueChange, delay, closeDelay, orientation, active, and closeOnClick.
NavigationMenu
| Prop | Type | Default | Description |
|---|---|---|---|
align | 'start' | 'center' | 'end' | 'start' | The edge of the trigger the popup is aligned with |
NavigationMenuPositioner
NavigationMenu renders this part and passes align to it. Its own defaults are side="bottom", sideOffset={8}, align="start", and alignOffset={0}.