ComponentsNavigationMenu
NavigationMenu
Group page links in a menu with optional dropdown panels.
On this page
Use this component from the local workspace package. Follow the setup guide first. A public npm package and registry are not available yet.
View registry filesImport the component into your page or component file.
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuIndicator,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
NavigationMenuViewport,
} from "@dethink/components";NavigationMenu keeps links as links. Triggers are disclosure buttons with aria-expanded, and panels stay in the navigation's tab order.
Simple link bar
Current, disabled, and external states on a persistent top navigation.
Show sourceexamples/navigation-menu/basic.tsx
"use client";
import {
NavigationMenu,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
} from "@dethink/components";
export function NavigationMenuBasic() {
return (
<NavigationMenu aria-label="Product">
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuLink current href="#overview">
Overview
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="#projects">Projects</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="#reports">Reports</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink disabled href="#billing">
Billing
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink external href="https://status.example.com">
Status
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
);
}Examples that combine components for common tasks.
Brand navbar
A full marketing navbar: brand logo, icon-led menu with rich flyouts and the animated indicator, plus a theme toggle, login, and call-to-action cluster. When the bar gets narrow, the burger expands an integrated panel with accordion submenus โ no overlay.
Product navigation
Rich flyout panels with a featured card, grouped links, icons, descriptions, and the animated indicator.
App topbar with mobile handoff
A compact quiet nav on desktop; on small screens the same links hand off to a Dialog. Resize the viewport to see the collapse.
Show sourceexamples/navigation-menu/app-topbar.tsx
"use client";
import {
Dialog,
DialogContent,
DialogTitle,
DialogTrigger,
NavigationMenu,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
} from "@dethink/components";
import { Menu } from "lucide-react";
const sections = [
{ href: "#dashboard", label: "Dashboard", current: true },
{ href: "#deployments", label: "Deployments", current: false },
{ href: "#monitoring", label: "Monitoring", current: false },
{ href: "#team", label: "Team", current: false },
];
export function NavigationMenuAppTopbar() {
return (
<header className="border-border bg-muted/30 flex items-center justify-between gap-4 rounded-md border px-4 py-2">
<span className="text-foreground text-sm font-semibold">Acme Cloud</span>
{/* Desktop: persistent quiet nav. */}
<NavigationMenu
aria-label="Dashboard"
variant="quiet"
size="sm"
className="max-md:hidden"
>
<NavigationMenuList>
{sections.map((section) => (
<NavigationMenuItem key={section.href}>
<NavigationMenuLink current={section.current} href={section.href}>
{section.label}
</NavigationMenuLink>
</NavigationMenuItem>
))}
</NavigationMenuList>
</NavigationMenu>
{/* Mobile: the same links hand off to a Dialog. NavigationMenu stays a
navigation primitive โ the Dialog owns the overlay behavior. */}
<div className="md:hidden">
<Dialog>
<DialogTrigger
aria-label="Open navigation"
size="icon"
variant="outline"
>
<Menu aria-hidden="true" className="size-4" />
</DialogTrigger>
<DialogContent>
<DialogTitle>Navigate</DialogTitle>
<div className="px-[var(--dt-space-6)] pb-[var(--dt-space-6)]">
<NavigationMenu
aria-label="Dashboard"
orientation="vertical"
variant="quiet"
>
<NavigationMenuList>
{sections.map((section) => (
<NavigationMenuItem key={section.href}>
<NavigationMenuLink
current={section.current}
href={section.href}
>
{section.label}
</NavigationMenuLink>
</NavigationMenuItem>
))}
</NavigationMenuList>
</NavigationMenu>
</div>
</DialogContent>
</Dialog>
</div>
<span className="text-muted-foreground text-sm max-md:hidden">
workspace: prod
</span>
</header>
);
}Mobile navigation drawer
A phone-sized in-page drawer: a disclosure button toggles the panel, and the vertical menu restyles its flyout into an accordion โ links, icons, current state, and auth actions stay intact.
Documentation hub
Underline variant with grouped guide flyouts and aria-current=location for the active page.
Show sourceexamples/navigation-menu/docs-hub.tsx
"use client";
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuDescription,
NavigationMenuItem,
NavigationMenuLabel,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuSection,
NavigationMenuSeparator,
NavigationMenuTrigger,
} from "@dethink/components";
export function NavigationMenuDocsHub() {
return (
<div className="min-h-[20rem]">
<NavigationMenu aria-label="Documentation" variant="underline">
<NavigationMenuList>
<NavigationMenuItem value="guides">
<NavigationMenuTrigger>Guides</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuSection>
<NavigationMenuLabel>Getting started</NavigationMenuLabel>
<NavigationMenuLink current="location" href="#install">
Installation
<NavigationMenuDescription>
Registry setup and base tokens.
</NavigationMenuDescription>
</NavigationMenuLink>
<NavigationMenuLink href="#theming">
Theming
<NavigationMenuDescription>
Light, dark, density, and brand palettes.
</NavigationMenuDescription>
</NavigationMenuLink>
</NavigationMenuSection>
<NavigationMenuSeparator orientation="vertical" />
<NavigationMenuSection>
<NavigationMenuLabel>Recipes</NavigationMenuLabel>
<NavigationMenuLink href="#forms">Forms</NavigationMenuLink>
<NavigationMenuLink href="#tables">Tables</NavigationMenuLink>
<NavigationMenuLink href="#navigation">
Navigation
</NavigationMenuLink>
</NavigationMenuSection>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem value="reference">
<NavigationMenuTrigger>Reference</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuSection>
<NavigationMenuLink href="#api">
Component API
</NavigationMenuLink>
<NavigationMenuLink href="#tokens">Tokens</NavigationMenuLink>
</NavigationMenuSection>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="#changelog">Changelog</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</div>
);
}Dashboard composition
A quiet topbar plus a vertical section nav composing an app shell โ without absorbing Sidebar's job.
Show sourceexamples/navigation-menu/dashboard.tsx
"use client";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
NavigationMenu,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
} from "@dethink/components";
export function NavigationMenuDashboard() {
return (
<div className="space-y-4">
<header className="border-border bg-muted/30 flex items-center justify-between gap-4 rounded-md border px-4 py-2">
<span className="text-foreground text-sm font-semibold">Insights</span>
<NavigationMenu aria-label="Workspace areas" size="sm" variant="quiet">
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuLink href="#home">Home</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink current href="#reports">
Reports
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="#alerts">Alerts</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</header>
<div className="grid gap-4 md:grid-cols-[12rem_minmax(0,1fr)]">
<NavigationMenu
aria-label="Report sections"
orientation="vertical"
size="sm"
variant="quiet"
>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuLink current="location" href="#revenue">
Revenue
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="#retention">
Retention
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="#usage">Usage</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
<Card>
<CardHeader>
<CardTitle>Revenue report</CardTitle>
<CardDescription>Updated from pipeline run #428.</CardDescription>
</CardHeader>
<CardContent>
<p className="text-muted-foreground text-sm">
Two NavigationMenu instances compose the shell: a quiet topbar for
workspace areas and a vertical section list for the active report.
A full application shell with a collapsible sidebar stays out of
scope for NavigationMenu โ that is the future Sidebar component.
</p>
</CardContent>
</Card>
</div>
</div>
);
}Overflow collapse
Secondary destinations collapse behind a More disclosure on narrow screens and render inline when space allows.
Show sourceexamples/navigation-menu/overflow.tsx
"use client";
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuSection,
NavigationMenuTrigger,
} from "@dethink/components";
export function NavigationMenuOverflow() {
return (
<div className="min-h-[16rem]">
<NavigationMenu aria-label="Product">
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuLink current href="#overview">
Overview
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="#projects">Projects</NavigationMenuLink>
</NavigationMenuItem>
{/* Secondary destinations stay reachable on narrow screens by
collapsing behind a disclosure trigger instead of wrapping. */}
<NavigationMenuItem className="lg:hidden" value="more">
<NavigationMenuTrigger>More</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuSection>
<NavigationMenuLink href="#reports">Reports</NavigationMenuLink>
<NavigationMenuLink href="#audit">Audit log</NavigationMenuLink>
<NavigationMenuLink href="#settings">
Settings
</NavigationMenuLink>
</NavigationMenuSection>
</NavigationMenuContent>
</NavigationMenuItem>
{/* On wide screens the same links render inline. */}
<NavigationMenuItem className="max-lg:hidden">
<NavigationMenuLink href="#reports">Reports</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem className="max-lg:hidden">
<NavigationMenuLink href="#audit">Audit log</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem className="max-lg:hidden">
<NavigationMenuLink href="#settings">Settings</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</div>
);
}| Prop | What it does | Default |
|---|---|---|
variant / size / orientation"default" | "quiet" | "underline" / "sm" | "md" | "lg" / "horizontal" | "vertical" | Token-backed presentation of the whole menu; links and triggers inherit these through context. | "default" / "md" / "horizontal" |
value / defaultValue / onValueChangestring | null / string | null / (value) => void | Controlled or uncontrolled open flyout item, keyed by NavigationMenuItem value. | Not set |
activationMode"click" | "hover" | "focus" | "manual" | How triggers open panels. Hover adds an intent delay and keeps click/keyboard activation working; manual leaves all state changes to the consumer. | "click" |
delay / closeDelaynumber / number | Hover-intent timings in milliseconds for hover activation. | 150 / 300 |
motion"none" | "subtle" | "standard" | "expressive" | CSS motion preset for panel transitions, directional slides, and staggered reveal. All movement respects prefers-reduced-motion. | "standard" |
NavigationMenuLink โ currentboolean | "page" | "location" | Marks the current destination with aria-current and a stable data-current attribute. | Not set |
NavigationMenuLink โ disabled / external / icon / asChildboolean / boolean / ReactNode / boolean | Disabled links drop their href and expose aria-disabled; external links get safe rel handling; asChild composes router links. | Not set |
NavigationMenuItem โ valuestring | Stable identity for controlled state, indicator mapping, and directional transitions. | auto |
NavigationMenuTriggerbutton (disclosure semantics) | Native button exposing aria-expanded/aria-controls; never role=menu. showChevron hides the built-in caret. | Not set |
NavigationMenuViewport / NavigationMenuIndicatoroptional anatomy | Shared morphing panel host and animated active-item marker; both are optional layers over the inline flyout behavior. | Not set |