import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle,
} from "@/components/ui/navigation-menu";
import { preventNavigation } from "@/examples/data";
const products = [
{ title: "Projects", description: "Plan work in lists, boards and timelines." },
{ title: "Docs", description: "Write specs and notes next to the work." },
{ title: "Insights", description: "Track progress across every team." },
{ title: "Automations", description: "Hand repetitive steps to rules." },
];
const resources = ["Guides", "Changelog", "Community", "Support"];
export default function NavigationMenuBasic() {
return (
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Product</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-[30rem] max-w-full grid-cols-1 sm:grid-cols-2">
{products.map((product) => (
<li key={product.title}>
<NavigationMenuLink href="#" onClick={preventNavigation}>
<span className="font-medium">{product.title}</span>
<span className="text-muted-foreground">{product.description}</span>
</NavigationMenuLink>
</li>
))}
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuTrigger>Resources</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="flex w-48 flex-col">
{resources.map((resource) => (
<li key={resource}>
<NavigationMenuLink href="#" onClick={preventNavigation}>
{resource}
</NavigationMenuLink>
</li>
))}
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink
href="#"
onClick={preventNavigation}
className={navigationMenuTriggerStyle()}
>
Pricing
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
);
}- Add the registryOnce per project
pnpm dlx shadcn@latest registry add @jarvis=https://ui.jarv.is/r/{name}.json - Add navigation-menu
pnpm dlx shadcn@latest add @jarvis/navigation-menu
Usage
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle,
} from "@/components/ui/navigation-menu";
export function SiteNavigation() {
return (
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Product</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuLink href="/projects">Projects</NavigationMenuLink>
<NavigationMenuLink href="/docs">Docs</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="/pricing" className={navigationMenuTriggerStyle()}>
Pricing
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
);
}Each NavigationMenuItem holds either a link or a trigger with content. Use
navigationMenuTriggerStyle() to make a plain link match the triggers.
For menus of actions rather than links, use a Dropdown Menu or a Menubar.
Composition
Examples
With icons
import {
BookOpenIcon,
CodeIcon,
LifeBuoyIcon,
NewspaperIcon,
PaletteIcon,
ZapIcon,
} from "lucide-react";
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from "@/components/ui/navigation-menu";
import { preventNavigation } from "@/examples/data";
const developers = [
{ title: "API reference", description: "Every endpoint, with examples.", icon: CodeIcon },
{ title: "Webhooks", description: "React to changes as they happen.", icon: ZapIcon },
{ title: "Theming", description: "Match the embed to your brand.", icon: PaletteIcon },
];
const learn = [
{ title: "Guides", description: "Step-by-step walkthroughs.", icon: BookOpenIcon },
{ title: "Blog", description: "News and stories from the team.", icon: NewspaperIcon },
{ title: "Support", description: "Talk to a person.", icon: LifeBuoyIcon },
];
const sections = [
{ label: "Developers", links: developers },
{ label: "Learn", links: learn },
];
export default function NavigationMenuWithIcons() {
return (
<NavigationMenu>
<NavigationMenuList>
{sections.map((section) => (
<NavigationMenuItem key={section.label}>
<NavigationMenuTrigger>{section.label}</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="flex w-72 flex-col">
{section.links.map(({ title, description, icon: Icon }) => (
<li key={title}>
<NavigationMenuLink
href="#"
onClick={preventNavigation}
className="flex-row items-start gap-2.5"
>
<Icon className="mt-0.5" />
<span className="flex flex-col gap-0.5">
<span className="font-medium">{title}</span>
<span className="text-muted-foreground">{description}</span>
</span>
</NavigationMenuLink>
</li>
))}
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
))}
</NavigationMenuList>
</NavigationMenu>
);
}Active link
Set active on the link to the current page.
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle,
} from "@/components/ui/navigation-menu";
import { preventNavigation } from "@/examples/data";
const settings = ["Profile", "Security", "Notifications", "Billing"];
export default function NavigationMenuActiveLink() {
return (
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuLink
href="#"
onClick={preventNavigation}
className={navigationMenuTriggerStyle()}
>
Overview
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuTrigger>Settings</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="flex w-44 flex-col">
{settings.map((page) => (
<li key={page}>
<NavigationMenuLink
href="#"
onClick={preventNavigation}
active={page === "Security"}
>
{page}
</NavigationMenuLink>
</li>
))}
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
);
}Client-side routing
Pass your router's link to render.
import { Link } from "@tanstack/react-router";
import { NavigationMenuLink } from "@/components/ui/navigation-menu";
export function DocsLink() {
return <NavigationMenuLink render={<Link to="/docs" />}>Docs</NavigationMenuLink>;
}Props
NavigationMenu also takes side, sideOffset, align and alignOffset to position the panel.
The tables leave out className, style and render. Parts built on Base UI take them as its styling and composition guides describe.
NavigationMenu
| Prop | Type | Default |
|---|---|---|
actionsRefA ref to imperative actions.
| React.RefObject<NavigationMenuRootActions | null> | — |
onOpenChangeCompleteEvent handler called after any animations complete when the navigation menu is closed. | ((open: boolean) => void) | — |
valueThe controlled value of the navigation menu item that should be currently open. When non-nullish, the menu will be open. When nullish, the menu will be closed. To render an uncontrolled navigation menu, use the | any | null |
defaultValueThe uncontrolled value of the item that should be initially selected. To render a controlled navigation menu, use the | any | null |
onValueChangeCallback fired when the value changes. | ((value: any, eventDetails: NavigationMenu.Root.ChangeEventDetails) => void) | — |
delayHow long to wait before opening the navigation popup. Specified in milliseconds. | number | 50 |
closeDelayHow long to wait before closing the navigation popup. Specified in milliseconds. | number | 50 |
orientationThe orientation of the navigation menu. | "horizontal" | "vertical" | 'horizontal' |
sideWhich side of the anchor element to align the popup against. May automatically change to avoid collisions. | "bottom" | "inline-end" | "inline-start" | "left" | "right" | "top" | "bottom" |
sideOffsetDistance between the anchor and the popup in pixels. Also accepts a function that returns the distance to read the dimensions of the anchor and positioner elements, along with its side and alignment. The function takes a
| number | OffsetFunction | 4 |
alignHow to align the popup relative to the specified side. | "center" | "end" | "start" | "start" |
alignOffsetAdditional offset along the alignment axis in pixels. Also accepts a function that returns the offset to read the dimensions of the anchor and positioner elements, along with its side and alignment. The function takes a
| number | OffsetFunction | 0 |
NavigationMenuItem
| Prop | Type | Default |
|---|---|---|
valueA unique value that identifies this navigation menu item. If no value is provided, a unique ID will be generated automatically. Use when controlling the navigation menu programmatically. | any | — |
NavigationMenuTrigger
| Prop | Type | Default |
|---|---|---|
disabledWhether the component should ignore user interaction. | boolean | false |
nativeButtonWhether the component renders a native | boolean | true |
NavigationMenuContent
| Prop | Type | Default |
|---|---|---|
keepMountedWhether to keep the content mounted in the DOM while the popup is closed. Ensures the content is present during server-side rendering for web crawlers. | boolean | false |
NavigationMenuLink
| Prop | Type | Default |
|---|---|---|
activeWhether the link is the currently active page. | boolean | false |
closeOnClickWhether to close the navigation menu when the link is clicked. | boolean | false |