Capítulo 38 de 108

Navigation Menu

Core Idea

A collection of links for navigating websites, with dropdown-style content panels per top-level item. Use for site headers/main nav with grouped links, not for breadcrumb trails or sidebars.

Key Concepts

  • navigationMenuTriggerStyle(): helper function that returns the trigger's className, used to style a plain NavigationMenuLink (a top-level item without a dropdown) consistently with NavigationMenuTrigger items.
  • render prop on NavigationMenuLink: swaps in a custom link component (e.g. Next.js Link) — same pattern as Breadcrumb: render={<Link href="/docs" />}.
  • NavigationMenuTrigger: top-level item that opens a NavigationMenuContent panel on hover/focus.
  • NavigationMenuIndicator: optional visual indicator (arrow/caret) tracking the active trigger, part of the full composition tree.
  • dir + align: for RTL, pass dir={dir} to NavigationMenu and to each NavigationMenuContent, and flip align (align={dir === "rtl" ? "end" : "start"}).

Code Examples

<NavigationMenu>
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuTrigger>Item One</NavigationMenuTrigger>
      <NavigationMenuContent>
        <NavigationMenuLink>Link</NavigationMenuLink>
      </NavigationMenuContent>
    </NavigationMenuItem>
  </NavigationMenuList>
</NavigationMenu>
  • O que demonstra: composição mínima de um item com dropdown.
import Link from "next/link"
import { NavigationMenuItem, NavigationMenuLink, navigationMenuTriggerStyle } from "@/components/ui/navigation-menu"

<NavigationMenuItem>
  <NavigationMenuLink
    render={<Link href="/docs" />}
    className={navigationMenuTriggerStyle()}
  >
    Documentation
  </NavigationMenuLink>
</NavigationMenuItem>
  • O que demonstra: item de nível superior sem dropdown, estilizado igual aos triggers com navigationMenuTriggerStyle().
function ListItem({ title, children, href, ...props }: React.ComponentPropsWithoutRef<"li"> & { href: string }) {
  return (
    <li {...props}>
      <NavigationMenuLink render={<Link href={href} />}>
        <div className="flex flex-col gap-1 text-sm">
          <div className="leading-none font-medium">{title}</div>
          <div className="line-clamp-2 text-muted-foreground">{children}</div>
        </div>
      </NavigationMenuLink>
    </li>
  )
}
  • O que demonstra: padrão de item de lista customizado dentro de NavigationMenuContent para menus com título+descrição (mega menu).

Composition

NavigationMenu
├── NavigationMenuList
│   ├── NavigationMenuItem
│   │   ├── NavigationMenuTrigger
│   │   └── NavigationMenuContent
│   │       ├── NavigationMenuLink
│   │       └── NavigationMenuLink
│   └── NavigationMenuItem
│       └── NavigationMenuLink
└── NavigationMenuIndicator

Anti-patterns

  • Colocar todo item como NavigationMenuTrigger, mesmo sem submenu: um item de link direto (sem dropdown) deve ser NavigationMenuLink + navigationMenuTriggerStyle(), não um Trigger com Content vazio.
  • Não propagar dir/align em RTL: sem isso o menu abre para o lado errado em locales RTL.

Key Takeaways

  1. Itens com submenu usam NavigationMenuTrigger+NavigationMenuContent; itens simples usam NavigationMenuLink direto com navigationMenuTriggerStyle() para manter visual consistente.
  2. Integração com router (Next.js Link etc.) é sempre via prop render, nunca asChild.
  3. Mega menus (grid de cards com título+descrição) são construídos com um componente ListItem custom, não uma prop pronta da lib.
  4. RTL requer dir tanto no NavigationMenu raiz quanto em cada NavigationMenuContent, mais inversão manual de align.

Connects To

  • Breadcrumb: outro componente de navegação, mas para trilha hierárquica, não menu de topo.
  • DropdownMenu: primitivo de menu mais genérico; NavigationMenu é especializado para nav bars com hover/mega menu.
  • Sidebar: alternativa de navegação lateral, geralmente usada junto com um header simples em vez de NavigationMenu.