Skip to content

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.

On this page

Example

Loading example…
Navigation Menu.tsxtsx
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.

  1. NavigationMenu

    Navigation landmark that keeps a single panel open at a time. Owns a DOM element.

  2. NavigationMenuList

    Native list of navigation items. Owns a DOM element.

  3. NavigationMenuItem

    List item pairing one trigger with its panel. Owns a DOM element.

  4. NavigationMenuTrigger

    Native button that toggles its item's panel; hovering opens it after a short intent delay. Owns a DOM element.

  5. NavigationMenuContent

    Inline panel of links; it stays in the page flow so CSS positions it. Owns a DOM element.

  6. NavigationMenuLink

    Native anchor to a destination; activating it closes the open panel. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Start NavigationMenu with NavigationMenuList around the items.

  2. 2

    Add the supporting parts

    Give each NavigationMenuItem a value, then pair a NavigationMenuTrigger with its NavigationMenuContent panel of links.

  3. 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

Importtsx
import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger } from "@comp0/react";

NavigationMenu

DOM element

Navigation landmark that keeps a single panel open at a time.

PropTypeDescription
aria-labelstringNames the landmark when the page has more than one nav.
valuestringControlled open item; "" means every panel is closed.
defaultValuestringInitial open item; "" means every panel is closed.
onChange(value: string) => voidReceives the next open item value.

NavigationMenuList

DOM element

Native list of navigation items.

NavigationMenuItem

DOM element

List item pairing one trigger with its panel.

PropTypeDescription
valuestringIdentity that pairs the trigger with its content panel.

NavigationMenuTrigger

DOM element

Native button that toggles its item's panel; hovering opens it after a short intent delay.

PropTypeDescription
asElementType | FragmentFragment merges the trigger onto your own element child.

NavigationMenuContent

DOM element

Inline panel of links; it stays in the page flow so CSS positions it.

NavigationMenuLink

DOM element

Native anchor to a destination; activating it closes the open panel.

PropTypeDescription
hrefstringDestination URL.
currentbooleanMarks the page you are on with aria-current="page".
asElementTypeRenders 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 hookMeaning
[data-open]Some panel is open.

NavigationMenuItem

Style hookMeaning
[data-open]This item's panel is open.

NavigationMenuTrigger

Style hookMeaning
[data-open]This item's panel is open.

NavigationMenuContent

Style hookMeaning
[data-open]This item's panel is open.

NavigationMenuLink

Style hookMeaning
[aria-current]This link is the current page.
[data-current]Presence hook mirroring aria-current for styling.

Keep exploring