Navigation Menu

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.json

Needs 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

'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

NameTypeDefaultDescription
NavigationMenunav props—The root. Renders the shared panel that dropdowns open into, which animates its size and position between items.
NavigationMenuItem valuestring—Identifies an item that has a trigger and content.
NavigationMenuTriggerbutton props—Opens its content on hover or focus; Enter, Space and ArrowDown also open it.
NavigationMenuContentdiv props—The panel's content. Slides in from the side of the previous item.
NavigationMenuLink activebooleanfalseMarks the current page; shows the indicator bar.
NavigationMenuLinkCard titlestring—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 / closeDelaynumber50 / 50Milliseconds before hover opens or closes the panel.