Navigation
Navigation Menu
A site nav where some links unfold into small panels of more links.
When to use it: Use it for site-wide navigation with grouped destinations; use Menubar for application commands.
Example
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from "@comp0/react";
import { ChevronDownIcon } from "@heroicons/react/16/solid";
export function Example() {
return (
<NavigationMenu
aria-label="Main"
className="relative w-full max-w-md rounded border border-zinc-950/10 p-1 dark:border-white/10"
>
<NavigationMenuList className="flex flex-wrap items-center gap-1">
<NavigationMenuItem value="products">
<NavigationMenuTrigger className="group flex items-center gap-1 rounded px-3 py-2.5 text-base text-zinc-800 select-none hover:bg-zinc-100 data-open:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800 dark:data-open:bg-zinc-800">
Products
<ChevronDownIcon
className="size-4 text-zinc-400 transition-transform duration-150 ease-out group-data-open:rotate-180 motion-reduce:transition-none"
aria-hidden="true"
/>
</NavigationMenuTrigger>
<NavigationMenuContent className="absolute inset-x-1 top-full z-10 mt-1 grid gap-1 rounded border-0 bg-white p-1 opacity-100 shadow-lg ring-1 ring-zinc-950/10 transition-opacity duration-150 ease-out starting:opacity-0 motion-reduce:transition-none dark:bg-zinc-900 dark:shadow-none dark:ring-white/10">
<NavigationMenuLink
href="#analytics"
className="rounded px-3 py-2.5 text-base text-zinc-800 hover:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800"
>
Analytics
</NavigationMenuLink>
<NavigationMenuLink
href="#dashboards"
className="rounded px-3 py-2.5 text-base text-zinc-800 hover:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800"
>
Dashboards
</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem value="resources">
<NavigationMenuTrigger className="group flex items-center gap-1 rounded px-3 py-2.5 text-base text-zinc-800 select-none hover:bg-zinc-100 data-open:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800 dark:data-open:bg-zinc-800">
Resources
<ChevronDownIcon
className="size-4 text-zinc-400 transition-transform duration-150 ease-out group-data-open:rotate-180 motion-reduce:transition-none"
aria-hidden="true"
/>
</NavigationMenuTrigger>
<NavigationMenuContent className="absolute inset-x-1 top-full z-10 mt-1 grid gap-1 rounded border-0 bg-white p-1 opacity-100 shadow-lg ring-1 ring-zinc-950/10 transition-opacity duration-150 ease-out starting:opacity-0 motion-reduce:transition-none dark:bg-zinc-900 dark:shadow-none dark:ring-white/10">
<NavigationMenuLink
href="#docs"
className="rounded px-3 py-2.5 text-base text-zinc-800 hover:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800"
>
Documentation
</NavigationMenuLink>
<NavigationMenuLink
href="#guides"
className="rounded px-3 py-2.5 text-base text-zinc-800 hover:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800"
>
Guides
</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem value="pricing">
<NavigationMenuLink
href="#pricing"
className="block rounded px-3 py-2.5 text-base text-zinc-800 select-none hover:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800"
>
Pricing
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
);
}Anatomy
Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.
A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.
NavigationMenu
Navigation landmark that keeps a single panel open at a time. Owns a DOM element.
NavigationMenuList
Native list of navigation items. Owns a DOM element.
NavigationMenuItem
List item pairing one trigger with its panel. Owns a DOM element.
NavigationMenuTrigger
Native button that toggles its item's panel; hovering opens it after a short intent delay. Owns a DOM element.
NavigationMenuContent
Inline panel of links; it stays in the page flow so CSS positions it. Owns a DOM element.
NavigationMenuLink
Native anchor to a destination; activating it closes the open panel. Owns a DOM element.
Step by step
- 1
Add the main part
Start NavigationMenu with NavigationMenuList around the items.
- 2
Add the supporting parts
Give each NavigationMenuItem a value, then pair a NavigationMenuTrigger with its NavigationMenuContent panel of links.
- 3
Make the behavior clear
Use NavigationMenuLink for every destination and mark the page you are on with current.
Exampletsx <NavigationMenu aria-label="Main"> <NavigationMenuList> <NavigationMenuItem value="products"> <NavigationMenuTrigger>Products</NavigationMenuTrigger> <NavigationMenuContent> <NavigationMenuLink href="/analytics">Analytics</NavigationMenuLink> </NavigationMenuContent> </NavigationMenuItem> </NavigationMenuList> </NavigationMenu>;
Keyboard
- ⇥
- Moves through triggers and links in document order.
- ↵
- Toggles the focused trigger's panel.
- Space
- Toggles the focused trigger's panel.
- Esc
- Closes the open panel and returns focus to its trigger.
- ↓→
- Moves to the next top-level stop, or from an expanded trigger to its panel's first link. · top-level row
- ↓→
- Moves to the next link in the panel. · panel link
- ↑←
- Moves to the previous stop or link; movement never wraps.
- Home
- Moves to the first stop or the panel's first link.
- End
- Moves to the last stop or the panel's last link.
Forms and accessibility
No native form behavior.
Accessibility checklist
- Give the nav an aria-label when the page has more than one navigation landmark.
- Triggers are disclosure buttons, not role="menu" items; Tab moves through triggers and links in document order, and arrow keys, Home, and End move focus without opening panels.
- Horizontal arrow movement follows visual direction and mirrors in RTL.
- Mark the page you are on with current instead of relying on styling alone.
- Panels stay in the page flow; keep each one right after its trigger so reading order matches the visual order.
API reference
import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger } from "@comp0/react";NavigationMenu
DOM elementNavigation landmark that keeps a single panel open at a time.
| Prop | Type | Description |
|---|---|---|
aria-label | string | Names the landmark when the page has more than one nav. |
value | string | Controlled open item; "" means every panel is closed. |
defaultValue | string | Initial open item; "" means every panel is closed. |
onChange | (value: string) => void | Receives the next open item value. |
NavigationMenuList
DOM elementNative list of navigation items.
NavigationMenuItem
DOM elementList item pairing one trigger with its panel.
| Prop | Type | Description |
|---|---|---|
value | string | Identity that pairs the trigger with its content panel. |
NavigationMenuTrigger
DOM elementNative button that toggles its item's panel; hovering opens it after a short intent delay.
| Prop | Type | Description |
|---|---|---|
as | ElementType | Fragment | Fragment merges the trigger onto your own element child. |
NavigationMenuContent
DOM elementInline panel of links; it stays in the page flow so CSS positions it.
NavigationMenuLink
DOM elementNative anchor to a destination; activating it closes the open panel.
| Prop | Type | Description |
|---|---|---|
href | string | Destination URL. |
current | boolean | Marks the page you are on with aria-current="page". |
as | ElementType | Renders a router link instead of the native anchor. |
Style hooks
Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.
NavigationMenu
| Style hook | Meaning |
|---|---|
[data-open] | Some panel is open. |
NavigationMenuItem
| Style hook | Meaning |
|---|---|
[data-open] | This item's panel is open. |
NavigationMenuTrigger
| Style hook | Meaning |
|---|---|
[data-open] | This item's panel is open. |
NavigationMenuContent
| Style hook | Meaning |
|---|---|
[data-open] | This item's panel is open. |
NavigationMenuLink
| Style hook | Meaning |
|---|---|
[aria-current] | This link is the current page. |
[data-current] | Presence hook mirroring aria-current for styling. |