A top navigation bar with animated dropdown panels and links.
'use client'
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuLinkCard,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle,
} from '@/components/ui/navigation-menu'
const components = [
{ title: 'Dialog', description: 'A window over the page that asks for a decision or input.' },
{ title: 'Dropdown Menu', description: 'A menu of actions, opened from a trigger.' },
{ title: 'Tabs', description: 'Layered sections of content, one visible at a time.' },
{ title: 'Toast', description: 'A short, stacked notification that dismisses itself.' },
]
/** Hover or focus a trigger to open its panel; arrow keys move between triggers, Escape closes. */
export default function NavigationMenuDemo() {
return (
<NavigationMenu>
<NavigationMenuList className="flex-wrap justify-center">
<NavigationMenuItem value="getting-started">
<NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid gap-1 sm:w-[26rem] sm:grid-cols-[1.1fr_1fr]">
<li className="sm:row-span-3">
<NavigationMenuLink
href="#introduction"
className="flex h-full min-h-28 flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-4 no-underline transition-colors hover:bg-accent focus-visible:ring-ring/50 focus-visible:ring-[3px]"
>
<div className="mb-1 text-base font-medium">Kagadmodyaa</div>
<p className="text-[13px] leading-snug text-muted-foreground">Components you copy, own and change.</p>
</NavigationMenuLink>
</li>
<li>
<NavigationMenuLinkCard href="#installation" title="Installation">
Add the CLI and your first component.
</NavigationMenuLinkCard>
</li>
<li>
<NavigationMenuLinkCard href="#theming" title="Theming">
Tokens for colour, radius and dark mode.
</NavigationMenuLinkCard>
</li>
<li>
<NavigationMenuLinkCard href="#accessibility" title="Accessibility">
Keyboard and screen reader behaviour.
</NavigationMenuLinkCard>
</li>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem value="components">
<NavigationMenuTrigger>Components</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid gap-1 sm:w-[30rem] sm:grid-cols-2">
{components.map(component => (
<li key={component.title}>
<NavigationMenuLinkCard href={`#${component.title.toLowerCase().replace(/\s+/g, '-')}`} title={component.title}>
{component.description}
</NavigationMenuLinkCard>
</li>
))}
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="#docs" active className={navigationMenuTriggerStyle()}>
Docs
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
)
}
Built on Base UI
Installation
pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/navigation-menu.jsonNeeds a React + Tailwind project set up with shadcn. Copies the component source straight into your project, so you can edit it.
Navigation Menu imports cn() from lib/utils.ts — add it too if you don't have it yet:
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Usage
import {
NavigationMenu,
NavigationMenuList,
NavigationMenuItem,
NavigationMenuTrigger,
NavigationMenuContent,
NavigationMenuLink,
NavigationMenuLinkCard,
navigationMenuTriggerStyle,
} from '@/components/ui/navigation-menu'
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem value="products">
<NavigationMenuTrigger>Products</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuLinkCard href="/analytics" title="Analytics">
Understand your users.
</NavigationMenuLinkCard>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="/pricing" className={navigationMenuTriggerStyle()}>
Pricing
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>Examples
Links with an active indicator
'use client'
import {
NavigationMenu,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
navigationMenuTriggerStyle,
} from '@/components/ui/navigation-menu'
const links = ['Overview', 'Customers', 'Reports', 'Settings']
/** Plain links only — `active` marks the current page with the indicator bar. */
export default function NavigationMenuLinks() {
return (
<NavigationMenu>
<NavigationMenuList className="flex-wrap justify-center">
{links.map(label => (
<NavigationMenuItem key={label}>
<NavigationMenuLink href={`#${label.toLowerCase()}`} active={label === 'Reports'} className={navigationMenuTriggerStyle()}>
{label}
</NavigationMenuLink>
</NavigationMenuItem>
))}
</NavigationMenuList>
</NavigationMenu>
)
}
API Reference
| Name | Type | Default | Description |
|---|---|---|---|
| NavigationMenu | nav props | — | The root. Renders the shared panel that dropdowns open into, which animates its size and position between items. |
| NavigationMenuItem value | string | — | Identifies an item that has a trigger and content. |
| NavigationMenuTrigger | button props | — | Opens its content on hover or focus; Enter, Space and ArrowDown also open it. |
| NavigationMenuContent | div props | — | The panel's content. Slides in from the side of the previous item. |
| NavigationMenuLink active | boolean | false | Marks the current page; shows the indicator bar. |
| NavigationMenuLinkCard title | string | — | A link with a title and a short description, for grids. |
| navigationMenuTriggerStyle() | (className?) => string | — | The trigger classes, so a plain link can match. |
| NavigationMenu delay / closeDelay | number | 50 / 50 | Milliseconds before hover opens or closes the panel. |