Summit
ComponentsNavigation

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 menu role (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

ElementUsage
TriggerOptional
CaretOn every trigger
LinkOptional

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

KeyResult
TabMoves focus to each trigger and link in the row. From an open trigger, focus enters the panel first.
ArrowRight, ArrowLeftMoves 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 triggerOpens or closes its panel. Focus stays on the trigger.
ArrowDown on a triggerOpens its panel. Focus stays on the trigger.
ArrowDown, ArrowUp in a panelMoves focus to the next or the previous link. From the last link, focus moves to the first.
Enter on a linkFollows the link. An open panel stays open.
EscapeCloses 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-menu

Usage

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>;

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.

With a Router Link
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.

PropTypeDefaultDescription
align'start' | 'center' | 'end''start'The edge of the trigger the popup is aligned with

NavigationMenu renders this part and passes align to it. Its own defaults are side="bottom", sideOffset={8}, align="start", and alignOffset={0}.

On this page