HextaUI

Navigation menu

Navegação do site com dropdowns, ou um único painel de largura total que permanece aberto enquanto o conteúdo desliza entre os menus.

import {
  IconBook,
  IconBrandGithub,
  IconBuildingStore,
  IconChartBar,
  IconCode,
  IconComponents,
  IconLayoutDashboard,
  IconLifebuoy,
  IconPalette,
  IconRocket,
  IconShieldLock,
  IconUsers,
} from "@tabler/icons-react"

import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
} from "@/components/ui/navigation-menu"

type Entry = {
  title: string
  description: string
  icon: typeof IconBook
}

const products: Entry[] = [
  {
    title: "Components",
    description: "Accessible building blocks with motion built in.",
    icon: IconComponents,
  },
  {
    title: "Blocks",
    description: "Full sections you can drop into a page.",
    icon: IconLayoutDashboard,
  },
  {
    title: "Themes",
    description: "Tokens for color, radius and type.",
    icon: IconPalette,
  },
  {
    title: "Templates",
    description: "Starter apps ready to deploy.",
    icon: IconBuildingStore,
  },
]

const solutions: Entry[] = [
  {
    title: "Startups",
    description: "Ship a polished product on day one.",
    icon: IconRocket,
  },
  {
    title: "Teams",
    description: "One system shared across every app.",
    icon: IconUsers,
  },
  {
    title: "Analytics",
    description: "Dashboards, tables and charts.",
    icon: IconChartBar,
  },
  {
    title: "Security",
    description: "Audited for accessibility and safe defaults.",
    icon: IconShieldLock,
  },
  {
    title: "Developers",
    description: "Typed APIs that read like shadcn.",
    icon: IconCode,
  },
  {
    title: "Open source",
    description: "Read every line on GitHub.",
    icon: IconBrandGithub,
  },
]

const resources: Entry[] = [
  {
    title: "Documentation",
    description: "Every component, example and prop.",
    icon: IconBook,
  },
  {
    title: "Support",
    description: "Questions, bugs and feature requests.",
    icon: IconLifebuoy,
  },
]

function Links({ entries }: { entries: Entry[] }) {
  return (
    <ul className="grid gap-1 sm:grid-cols-2">
      {entries.map((entry) => (
        <li key={entry.title}>
          <NavigationMenuLink href="#">
            <span className="flex size-9 shrink-0 items-center justify-center rounded-md bg-background ring-(length:--hairline) ring-border">
              <entry.icon className="text-foreground" />
            </span>
            <span className="flex min-w-0 flex-col">
              <span className="font-medium">{entry.title}</span>
              <span className="text-muted-foreground">{entry.description}</span>
            </span>
          </NavigationMenuLink>
        </li>
      ))}
    </ul>
  )
}

export function NavigationMenuDemo() {
  return (
    <div className="w-full max-w-2xl rounded-xl border px-2 py-1.5">
      <NavigationMenu variant="panel" aria-label="Main">
        <NavigationMenuList>
          <NavigationMenuItem>
            <NavigationMenuTrigger>Products</NavigationMenuTrigger>
            <NavigationMenuContent>
              <Links entries={products} />
            </NavigationMenuContent>
          </NavigationMenuItem>
          <NavigationMenuItem>
            <NavigationMenuTrigger>Solutions</NavigationMenuTrigger>
            <NavigationMenuContent>
              <Links entries={solutions} />
            </NavigationMenuContent>
          </NavigationMenuItem>
          <NavigationMenuItem>
            <NavigationMenuTrigger>Resources</NavigationMenuTrigger>
            <NavigationMenuContent>
              <Links entries={resources} />
            </NavigationMenuContent>
          </NavigationMenuItem>
          <NavigationMenuItem>
            <NavigationMenuLink href="#">Pricing</NavigationMenuLink>
          </NavigationMenuItem>
        </NavigationMenuList>
      </NavigationMenu>
    </div>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/navigation-menu.json

Adiciona o componente, os tokens de tema do HextaUI e quaisquer componentes do HextaUI dos quais ele depende.

import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
} from "@/components/ui/navigation-menu"
<NavigationMenu variant="panel" aria-label="Main">
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuTrigger>Products</NavigationMenuTrigger>
      <NavigationMenuContent>
        <NavigationMenuLink href="/components">Components</NavigationMenuLink>
      </NavigationMenuContent>
    </NavigationMenuItem>
    <NavigationMenuItem>
      <NavigationMenuLink href="/pricing">Pricing</NavigationMenuLink>
    </NavigationMenuItem>
  </NavigationMenuList>
</NavigationMenu>

Com variant="panel", um único card ocupa a barra inteira. Passar entre gatilhos o mantém aberto e no lugar: só o conteúdo desliza na direção em que você se moveu, e a altura suaviza para se ajustar. Nada fecha, reabre ou salta.

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

A variante dropdown padrão abre um card sob cada gatilho. Ao passar para o próximo gatilho, o mesmo card desliza até ele e se redimensiona para o novo conteúdo.

import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
} from "@/components/ui/navigation-menu"

const guides = [
  { title: "Installation", description: "Add HextaUI to a Next.js app." },
  { title: "Theming", description: "Colors, radius and dark mode." },
  { title: "Motion", description: "Durations, easing and reduced motion." },
]

const components = [
  "Accordion",
  "Button",
  "Dialog",
  "Menubar",
  "Table",
  "Tooltip",
]

export function NavigationMenuDropdown() {
  return (
    <NavigationMenu aria-label="Docs">
      <NavigationMenuList>
        <NavigationMenuItem>
          <NavigationMenuTrigger>Guides</NavigationMenuTrigger>
          <NavigationMenuContent>
            <ul className="flex w-72 flex-col gap-1">
              {guides.map((guide) => (
                <li key={guide.title}>
                  <NavigationMenuLink href="#">
                    <span className="flex flex-col">
                      <span className="font-medium">{guide.title}</span>
                      <span className="text-muted-foreground">
                        {guide.description}
                      </span>
                    </span>
                  </NavigationMenuLink>
                </li>
              ))}
            </ul>
          </NavigationMenuContent>
        </NavigationMenuItem>
        <NavigationMenuItem>
          <NavigationMenuTrigger>Components</NavigationMenuTrigger>
          <NavigationMenuContent>
            <ul className="grid w-80 grid-cols-2 gap-1">
              {components.map((name) => (
                <li key={name}>
                  <NavigationMenuLink href="#">{name}</NavigationMenuLink>
                </li>
              ))}
            </ul>
          </NavigationMenuContent>
        </NavigationMenuItem>
        <NavigationMenuItem>
          <NavigationMenuLink href="#">Blog</NavigationMenuLink>
        </NavigationMenuItem>
      </NavigationMenuList>
    </NavigationMenu>
  )
}

Página atual

Os links na barra parecem gatilhos. Marque a página atual com active, que também define aria-current="page".

import {
  NavigationMenu,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
} from "@/components/ui/navigation-menu"

const links = ["Overview", "Activity", "Settings"]

export function NavigationMenuActive() {
  return (
    <NavigationMenu aria-label="Project">
      <NavigationMenuList>
        {links.map((link) => (
          <NavigationMenuItem key={link}>
            <NavigationMenuLink href="#" active={link === "Activity"}>
              {link}
            </NavigationMenuLink>
          </NavigationMenuItem>
        ))}
      </NavigationMenuList>
    </NavigationMenu>
  )
}

Da direita para a esquerda

Os deslizamentos do conteúdo seguem a direção em que você se move, que se inverte em layouts da direita para a esquerda.

import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
} from "@/components/ui/navigation-menu"

const menus = [
  { label: "المنتجات", links: ["المكونات", "القوالب", "السمات"] },
  { label: "الموارد", links: ["التوثيق", "الدعم"] },
]

export function NavigationMenuRtl() {
  return (
    <div dir="rtl" className="w-full max-w-md rounded-xl border px-2 py-1.5">
      <NavigationMenu variant="panel" aria-label="الرئيسية">
        <NavigationMenuList>
          {menus.map((menu) => (
            <NavigationMenuItem key={menu.label}>
              <NavigationMenuTrigger>{menu.label}</NavigationMenuTrigger>
              <NavigationMenuContent>
                <ul className="grid grid-cols-2 gap-1">
                  {menu.links.map((link) => (
                    <li key={link}>
                      <NavigationMenuLink href="#">{link}</NavigationMenuLink>
                    </li>
                  ))}
                </ul>
              </NavigationMenuContent>
            </NavigationMenuItem>
          ))}
        </NavigationMenuList>
      </NavigationMenu>
    </div>
  )
}
TeclaAção
TabPercorre a barra e, de um gatilho aberto, entra no seu conteúdo.
EnterSpaceAbre ou fecha o menu do gatilho com foco.
↑↓Move entre os links do conteúdo aberto.
←→Move entre os gatilhos da barra.
EscFecha o menu e devolve o foco ao seu gatilho.
  • A raiz renderiza um <nav>. Dê a ela um aria-label quando a página tiver mais de uma.
  • Os gatilhos são botões que informam se o menu está aberto, e o foco volta a eles quando o menu fecha.
  • O deslizamento do conteúdo e o destaque deslizante viram fades quando o movimento reduzido está ativado.
PropTipoPadrão
variantdropdown abre sob cada gatilho. panel abre um único card de largura total sob a barra que fica parado enquanto o conteúdo desliza.
"dropdown" | "panel""dropdown"
showSafeAreaDesenha a área segura que mantém um menu aberto enquanto o ponteiro vai em direção a ele. Para depuração e demos.
booleanfalse
align
"start" | "center" | "end""start", or "center" for panel
sideOffset
number8
value
any–
defaultValue
any–
onValueChange
(value, details) => void–
delayEspera antes de abrir no hover, em ms.
number50
closeDelayEspera antes de fechar depois que o ponteiro sai, em ms.
number50
orientation
"horizontal" | "vertical""horizontal"
AtributoDescrição
data-slot="navigation-menu"A nav, com data-variant.
data-slot="navigation-menu-highlight"O fundo que desliza entre os gatilhos abertos.
data-slot="navigation-menu-popup"O card. Sua altura suaviza por --popup-height.
AtributoDescrição
data-slot="navigation-menu-trigger"Selecione os gatilhos no CSS.
data-popup-openPresente enquanto seu menu está aberto. O chevron vira.
AtributoDescrição
data-slot="navigation-menu-content"O conteúdo de um menu, com data-variant.
data-activation-direction"left", "right", "up" ou "down": onde estava o gatilho anterior. Controla o deslizamento.
--navigation-menu-link-radiusRaio dos cantos do link, concêntrico com o card.
PropTipoPadrão
activeMarca a página atual.
booleanfalse
render
ReactElement | (props, state) => ReactElement<a>
AtributoDescrição
data-slot="navigation-menu-link"Seleciona os links no CSS. Na barra, eles se dimensionam como gatilhos.
data-activePresente na página atual.