Navigation Menu
A collection of links for navigating websites.
When to Use
Use Navigation Menu when you need to:
- Provide top-level site navigation with categorised dropdown panels
- Show rich content in dropdowns such as featured pages, icons, or descriptions
- Offer a horizontal menu bar that collapses to a single viewport on desktop
- Mix dropdown triggers with direct navigation links in the same bar
- Build accessible mega-menus that support keyboard and screen reader users
When Not to Use
- Application-style menu bar with submenus — use Menubar
- Switching between content panels in the same view — use Tabs
- Showing the user’s current location in a hierarchy — use Breadcrumb
- Right-click or action menus — use Context Menu or Dropdown Menu
Default
Full navigation menu with a featured content panel and grid layouts inside dropdowns.
Simple
A compact menu combining a single dropdown with direct navigation links.
With Icons
Menu items decorated with leading icons for quick visual scanning.
{/* Use navigationMenuTriggerStyle() for links that look like triggers */}
<NavigationMenuItem>
<NavigationMenuLink
className={navigationMenuTriggerStyle()}
href="/docs"
>
Documentation
</NavigationMenuLink>
</NavigationMenuItem>UX & Design Guidelines
Visual Hierarchy
Limit top-level triggers to 5–7 items. Use bg-accent and text-accent-foreground for hover/active states to maintain visual consistency. For featured content inside a dropdown, a gradient from bg-muted/50 to bg-muted creates a tasteful highlight card.
Spacing & Layout
Dropdown panels use p-4 padding by default. Grid layouts (grid-cols-2 or grid-cols-[.75fr_1fr]) work well for content-rich menus. Keep gap-1 between NavigationMenuList items for consistent trigger spacing.
Responsive Behaviour
The viewport width is driven by --radix-navigation-menu-viewport-width so it adapts to content automatically. On narrow screens, consider collapsing the navigation into a Sheet or Drawer triggered by a hamburger icon, rather than shrinking the menu bar.
Color & Contrast
Trigger text uses text-foreground on bg-background, flipping to text-accent-foreground on bg-accent for hover and open states. The dropdown panel sits on bg-popover with text-popover-foreground, ensuring AA-compliant contrast in both light and dark modes.
Accessibility
Keyboard Navigation
- Tab — Move focus into and out of the navigation menu
- Enter or Space — Open/close a trigger’s dropdown, or activate a link
- ← → — Move focus between top-level triggers
- ↓ — Move focus into the open dropdown content
- Esc — Close the currently open dropdown and return focus to its trigger
Screen Reader Support
- The root element renders a
navlandmark — addaria-labelwhen the page contains multiple nav regions - Triggers announce expanded/collapsed state via
aria-expandedautomatically - Use
aria-current="page"on the link that represents the current page - Active links receive
data-active="true"for styling and assistive technology hooks
Focus Management
Focus is trapped within the open dropdown. Closing the dropdown returns focus to the trigger. A visible focus ring (focus-visible:ring-[3px]) is shown on both triggers and links, using ring-ring/50 to meet WCAG 2.1 AA focus indicator requirements.
Touch Targets
Triggers render at h-9 (36 px) with px-4 horizontal padding, meeting minimum 44 px tap-target recommendations when combined with gap-1 between items. Dropdown links include p-2 padding for comfortable touch interaction.
ARIA Attributes
{/* Root menu with accessible label */}
<NavigationMenu aria-label="Main navigation">
<NavigationMenuList>
<NavigationMenuItem>
{/* Trigger auto-manages aria-expanded and aria-controls */}
<NavigationMenuTrigger>Products</NavigationMenuTrigger>
<NavigationMenuContent>
{/* Links announce their text to screen readers */}
<NavigationMenuLink href="/analytics">
Analytics
</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
{/* Direct link — no aria-expanded needed */}
<NavigationMenuItem>
<NavigationMenuLink
className={navigationMenuTriggerStyle()}
href="/pricing"
aria-current="page" {/* mark current page */}
>
Pricing
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>Related Components
Menubar
A visually persistent menu common in desktop applications, with nested submenus and keyboard shortcuts.
Tabs
Switch between layered sections of content displayed one at a time within the same view.
Breadcrumb
Displays the path to the current resource using a hierarchy of links for quick back-navigation.
Dropdown Menu
A contextual menu of actions triggered by a button, with support for sub-menus, checkboxes, and radio items.
API Reference
The Navigation Menu is a compound component. Each sub-component accepts the props listed below in addition to standard HTML attributes.
NavigationMenu
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | — | Controlled value of the currently active menu item. |
| onValueChange | (value: string) => void | — | Callback invoked when the active menu item changes. |
| defaultValue | string | — | The value of the active item on initial render (uncontrolled). |
| orientation | "horizontal" | "vertical" | "horizontal" | The layout direction of the menu items. |
| viewport | boolean | true | When true, renders a shared viewport container for dropdown content. Set to false for inline content. |
| className | string | — | Additional CSS classes applied to the root element. |
NavigationMenuTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
| childrenrequired | React.ReactNode | — | The trigger label. A chevron icon is appended automatically. |
| className | string | — | Additional CSS classes applied to the trigger button. |
NavigationMenuContent
| Prop | Type | Default | Description |
|---|---|---|---|
| forceMount | boolean | — | Force the content to stay mounted in the DOM. Useful when controlling entry/exit animations externally. |
| className | string | — | Additional CSS classes applied to the content container. |
NavigationMenuLink
| Prop | Type | Default | Description |
|---|---|---|---|
| active | boolean | false | Marks the link as the currently active page (adds data-active attribute). |
| asChild | boolean | false | When true, renders the child element directly, merging props. Use with Next.js Link or custom anchor tags. |
| className | string | — | Additional CSS classes applied to the link element. |