# Shadcn Navbar (Navigation Menu)

> Free shadcn/ui navbar built on the Navigation Menu (Radix). Dropdown menus, a simple link bar, a feature dropdown, a mega menu, active links, and a complete responsive navbar with a mobile hamburger Sheet.

Source: https://designrevision.com/components/navigation-menu

The **Shadcn Navbar** is built on the **Navigation Menu** — a Radix-based component for site navigation with links and animated dropdowns. Compose it into a flat link bar, a feature dropdown, a mega menu, or a **complete responsive navbar** with a mobile hamburger. The examples below cover all of those.

## Anatomy

```tsx
<NavigationMenu>
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuTrigger>Products</NavigationMenuTrigger>
      <NavigationMenuContent>{/* dropdown grid */}</NavigationMenuContent>
    </NavigationMenuItem>
    <NavigationMenuItem>
      <NavigationMenuLink className={navigationMenuTriggerStyle()} href="#">
        Docs
      </NavigationMenuLink>
    </NavigationMenuItem>
  </NavigationMenuList>
</NavigationMenu>
```

A `NavigationMenuItem` is either a **trigger + content** (a dropdown) or a plain **link**. Hover or focus opens the dropdowns, which animate inside a shared viewport.

## Building a navbar

A real navbar is a header row with three parts — **logo**, **nav**, **actions**:

```tsx
<header className="flex h-14 items-center justify-between border-b px-4">
  <Logo />
  <NavigationMenu className="hidden md:flex">{/* links */}</NavigationMenu>
  <Button size="sm">Sign up</Button>
</header>
```

The Responsive navbar example is the complete version.

## Responsive: the mobile menu

The Navigation Menu is hover-driven, so it's a desktop pattern. On small screens, **hide it** and show a **hamburger** that opens a **[Sheet](/components/sheet)** with the links stacked:

```tsx
<NavigationMenu className="hidden md:flex">…</NavigationMenu>

<Sheet>
  <SheetTrigger asChild>
    <Button variant="outline" size="icon" className="md:hidden"><Menu /></Button>
  </SheetTrigger>
  <SheetContent side="right">{/* stacked links */}</SheetContent>
</Sheet>
```

## Dropdowns & mega menus

- **Feature dropdown** — a grid of links with icons, titles, and descriptions (the Feature dropdown example).
- **Mega menu** — a wide `NavigationMenuContent` with a multi-column grid of grouped sections (the Mega menu example).

## Active link

Pass `active` to the link for the current route — it sets `data-active="true"` and the styles highlight it. Derive it from your router:

```tsx
<NavigationMenuLink active={pathname === href} href={href}>…</NavigationMenuLink>
```

## Navigation Menu vs Dropdown Menu vs Menubar

- **Navigation Menu** (this) — site navigation, a navbar with hover dropdowns of links.
- **[Dropdown Menu](/components/dropdown-menu)** — a click-triggered menu of *actions* (a row's "…" menu).
- **Menubar** — an application menu bar (File, Edit, View).

## Accessibility

Radix manages roles, keyboard navigation (arrow keys move between items, Escape closes), and focus. Dropdowns open on hover *and* focus so they're keyboard-reachable, and the active link carries `data-active` for styling. Provide a visible label on the mobile hamburger (an `sr-only` "Open menu" works).

## Installation

### navigation-menu

**Install:**

```bash
npx shadcn@latest add @designrevision/navigation-menu
```

**Dependencies:** @radix-ui/react-navigation-menu, class-variance-authority, utils

**Props**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| viewport | boolean | true | Render the shared viewport that animates dropdown size/position. Set false to position each NavigationMenuContent under its own item. |

**Usage & accessibility:** A Radix navbar with dropdown menus — the base for a site nav. Compose <NavigationMenu> → <NavigationMenuList> → <NavigationMenuItem>, each with a <NavigationMenuTrigger> + <NavigationMenuContent> (the dropdown) or a plain <NavigationMenuLink className={navigationMenuTriggerStyle()}>. Hover/focus opens menus, with a shared animated viewport (viewport=false to drop it per-item). Pair with Sheet for a mobile hamburger menu.

```tsx
// components/ui/navigation-menu.tsx
import * as React from "react"
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
import { cva } from "class-variance-authority"
import { ChevronDownIcon } from "lucide-react"

import { cn } from "@/lib/utils"

function NavigationMenu({
  className,
  children,
  viewport = true,
  ...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
  viewport?: boolean
}) {
  return (
    <NavigationMenuPrimitive.Root
      data-slot="navigation-menu"
      data-viewport={viewport}
      className={cn(
        "group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
        className
      )}
      {...props}
    >
      {children}
      {viewport && <NavigationMenuViewport />}
    </NavigationMenuPrimitive.Root>
  )
}

function NavigationMenuList({
  className,
  ...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
  return (
    <NavigationMenuPrimitive.List
      data-slot="navigation-menu-list"
      className={cn(
        "group flex flex-1 list-none items-center justify-center gap-1",
        className
      )}
      {...props}
    />
  )
}

function NavigationMenuItem({
  className,
  ...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
  return (
    <NavigationMenuPrimitive.Item
      data-slot="navigation-menu-item"
      className={cn("relative", className)}
      {...props}
    />
  )
}

const navigationMenuTriggerStyle = cva(
  "group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1"
)

function NavigationMenuTrigger({
  className,
  children,
  ...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
  return (
    <NavigationMenuPrimitive.Trigger
      data-slot="navigation-menu-trigger"
      className={cn(navigationMenuTriggerStyle(), "group", className)}
      {...props}
    >
      {children}{" "}
      <ChevronDownIcon
        className="relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180"
        aria-hidden="true"
      />
    </NavigationMenuPrimitive.Trigger>
  )
}

function NavigationMenuContent({
  className,
  ...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
  return (
    <NavigationMenuPrimitive.Content
      data-slot="navigation-menu-content"
      className={cn(
        "data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto",
        "group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none",
        className
      )}
      {...props}
    />
  )
}

function NavigationMenuViewport({
  className,
  ...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
  return (
    <div
      className={cn(
        "absolute top-full left-0 isolate z-50 flex justify-center"
      )}
    >
      <NavigationMenuPrimitive.Viewport
        data-slot="navigation-menu-viewport"
        className={cn(
          "origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow md:w-[var(--radix-navigation-menu-viewport-width)]",
          className
        )}
        {...props}
      />
    </div>
  )
}

function NavigationMenuLink({
  className,
  ...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
  return (
    <NavigationMenuPrimitive.Link
      data-slot="navigation-menu-link"
      className={cn(
        "data-[active=true]:focus:bg-accent data-[active=true]:hover:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring/50 [&_svg:not([class*='text-'])]:text-muted-foreground flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none focus-visible:ring-[3px] focus-visible:outline-1 [&_svg:not([class*='size-'])]:size-4",
        className
      )}
      {...props}
    />
  )
}

function NavigationMenuIndicator({
  className,
  ...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
  return (
    <NavigationMenuPrimitive.Indicator
      data-slot="navigation-menu-indicator"
      className={cn(
        "data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden",
        className
      )}
      {...props}
    >
      <div className="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
    </NavigationMenuPrimitive.Indicator>
  )
}

export {
  NavigationMenu,
  NavigationMenuList,
  NavigationMenuItem,
  NavigationMenuContent,
  NavigationMenuTrigger,
  NavigationMenuLink,
  NavigationMenuIndicator,
  NavigationMenuViewport,
  navigationMenuTriggerStyle,
}
```

## Examples

### Dropdown menus

The canonical navigation menu — triggers opening rich dropdown grids, plus a plain link.

**Install:**

```bash
npx shadcn@latest add @designrevision/navigation-menu-demo-01
```

**Dependencies:** navigation-menu

```tsx
// components/ui/navigation-menu-demo-01.tsx
import * as React from "react"

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

const components = [
  {
    title: "Alert Dialog",
    href: "#",
    description:
      "A modal dialog that interrupts the user with important content.",
  },
  {
    title: "Hover Card",
    href: "#",
    description: "For sighted users to preview content behind a link.",
  },
  {
    title: "Progress",
    href: "#",
    description: "Displays an indicator showing the completion of a task.",
  },
  {
    title: "Tabs",
    href: "#",
    description: "Layered sections of content shown one panel at a time.",
  },
]

function ListItem({
  title,
  children,
  href,
}: {
  title: string
  children: React.ReactNode
  href: string
}) {
  return (
    <li>
      <NavigationMenuLink asChild>
        <a
          href={href}
          className="hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground block space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors select-none"
        >
          <div className="text-sm leading-none font-medium">{title}</div>
          <p className="text-muted-foreground line-clamp-2 text-sm leading-snug">
            {children}
          </p>
        </a>
      </NavigationMenuLink>
    </li>
  )
}

export default function NavigationMenuDemo01() {
  return (
    <NavigationMenu>
      <NavigationMenuList>
        <NavigationMenuItem>
          <NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
          <NavigationMenuContent>
            <ul className="grid gap-2 p-4 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
              <li className="row-span-3">
                <NavigationMenuLink asChild>
                  <a
                    href="#"
                    className="from-muted/50 to-muted flex h-full w-full flex-col justify-end rounded-md bg-linear-to-b p-6 no-underline outline-none select-none focus:shadow-md"
                  >
                    <div className="mt-4 mb-2 text-lg font-medium">
                      shadcn/ui
                    </div>
                    <p className="text-muted-foreground text-sm leading-tight">
                      Beautifully designed components built with Tailwind CSS.
                    </p>
                  </a>
                </NavigationMenuLink>
              </li>
              <ListItem href="#" title="Introduction">
                Re-usable components built using Radix UI and Tailwind CSS.
              </ListItem>
              <ListItem href="#" title="Installation">
                How to install dependencies and structure your app.
              </ListItem>
              <ListItem href="#" title="Typography">
                Styles for headings, paragraphs, lists, and more.
              </ListItem>
            </ul>
          </NavigationMenuContent>
        </NavigationMenuItem>
        <NavigationMenuItem>
          <NavigationMenuTrigger>Components</NavigationMenuTrigger>
          <NavigationMenuContent>
            <ul className="grid w-[400px] gap-2 p-4 md:w-[500px] md:grid-cols-2">
              {components.map((component) => (
                <ListItem
                  key={component.title}
                  title={component.title}
                  href={component.href}
                >
                  {component.description}
                </ListItem>
              ))}
            </ul>
          </NavigationMenuContent>
        </NavigationMenuItem>
        <NavigationMenuItem>
          <NavigationMenuLink asChild className={cn(navigationMenuTriggerStyle())}>
            <a href="#">Docs</a>
          </NavigationMenuLink>
        </NavigationMenuItem>
      </NavigationMenuList>
    </NavigationMenu>
  )
}
```

---

### Simple link bar

A flat nav bar of links with no dropdowns — each styled with `navigationMenuTriggerStyle()`.

**Install:**

```bash
npx shadcn@latest add @designrevision/navigation-menu-simple-01
```

**Dependencies:** navigation-menu

```tsx
// components/ui/navigation-menu-simple-01.tsx
import {
  NavigationMenu,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  navigationMenuTriggerStyle,
} from "@/components/ui/navigation-menu"

const links = [
  { label: "Home", href: "#" },
  { label: "Features", href: "#" },
  { label: "Pricing", href: "#" },
  { label: "About", href: "#" },
]

export default function NavigationMenuSimple01() {
  return (
    <NavigationMenu>
      <NavigationMenuList>
        {links.map((link) => (
          <NavigationMenuItem key={link.label}>
            <NavigationMenuLink
              asChild
              className={navigationMenuTriggerStyle()}
            >
              <a href={link.href}>{link.label}</a>
            </NavigationMenuLink>
          </NavigationMenuItem>
        ))}
      </NavigationMenuList>
    </NavigationMenu>
  )
}
```

---

### Feature dropdown

A product dropdown with icons, titles, and descriptions — the feature-grid pattern.

**Install:**

```bash
npx shadcn@latest add @designrevision/navigation-menu-icons-01
```

**Dependencies:** lucide-react, navigation-menu

```tsx
// components/ui/navigation-menu-icons-01.tsx
import { BookOpen, LayoutGrid, LifeBuoy, Puzzle } from "lucide-react"

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

const features = [
  { icon: LayoutGrid, title: "Dashboard", desc: "Overview of your workspace." },
  { icon: Puzzle, title: "Integrations", desc: "Connect your favorite tools." },
  { icon: BookOpen, title: "Documentation", desc: "Guides and API reference." },
  { icon: LifeBuoy, title: "Support", desc: "Get help from our team." },
]

export default function NavigationMenuIcons01() {
  return (
    <NavigationMenu>
      <NavigationMenuList>
        <NavigationMenuItem>
          <NavigationMenuTrigger>Product</NavigationMenuTrigger>
          <NavigationMenuContent>
            <ul className="grid w-[420px] gap-1 p-2 md:grid-cols-2">
              {features.map((feature) => (
                <li key={feature.title}>
                  <NavigationMenuLink asChild>
                    <a
                      href="#"
                      className="hover:bg-accent flex flex-row items-start gap-3 rounded-md p-3"
                    >
                      <feature.icon className="text-muted-foreground size-5" />
                      <div>
                        <div className="text-sm leading-none font-medium">
                          {feature.title}
                        </div>
                        <p className="text-muted-foreground mt-1 text-sm leading-snug">
                          {feature.desc}
                        </p>
                      </div>
                    </a>
                  </NavigationMenuLink>
                </li>
              ))}
            </ul>
          </NavigationMenuContent>
        </NavigationMenuItem>
      </NavigationMenuList>
    </NavigationMenu>
  )
}
```

---

### Responsive navbar

A complete site navbar — desktop NavigationMenu plus a hamburger that opens a Sheet on mobile.

**Install:**

```bash
npx shadcn@latest add @designrevision/navigation-menu-navbar-01
```

**Dependencies:** lucide-react, navigation-menu, button, sheet

```tsx
// components/ui/navigation-menu-navbar-01.tsx
import { Menu } from "lucide-react"

import { Button } from "@/components/ui/button"
import {
  NavigationMenu,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  navigationMenuTriggerStyle,
} from "@/components/ui/navigation-menu"
import {
  Sheet,
  SheetContent,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet"

const links = [
  { label: "Home", href: "#" },
  { label: "Features", href: "#" },
  { label: "Pricing", href: "#" },
  { label: "About", href: "#" },
]

export default function NavigationMenuNavbar01() {
  return (
    <div className="w-full max-w-3xl">
      <header className="flex h-14 items-center justify-between rounded-lg border px-4">
        <a href="#" className="flex items-center gap-2 font-semibold">
          <div className="bg-primary text-primary-foreground flex size-7 items-center justify-center rounded-md text-sm">
            A
          </div>
          Acme
        </a>

        <NavigationMenu className="hidden md:flex">
          <NavigationMenuList>
            {links.map((link) => (
              <NavigationMenuItem key={link.label}>
                <NavigationMenuLink
                  asChild
                  className={navigationMenuTriggerStyle()}
                >
                  <a href={link.href}>{link.label}</a>
                </NavigationMenuLink>
              </NavigationMenuItem>
            ))}
          </NavigationMenuList>
        </NavigationMenu>

        <div className="flex items-center gap-2">
          <Button size="sm" className="hidden md:inline-flex">
            Sign up
          </Button>
          <Sheet>
            <SheetTrigger asChild>
              <Button variant="outline" size="icon" className="md:hidden">
                <Menu />
                <span className="sr-only">Open menu</span>
              </Button>
            </SheetTrigger>
            <SheetContent side="right" className="w-64">
              <SheetTitle className="px-4 pt-4">Acme</SheetTitle>
              <nav className="mt-4 flex flex-col gap-1 px-2">
                {links.map((link) => (
                  <a
                    key={link.label}
                    href={link.href}
                    className="hover:bg-accent rounded-md px-3 py-2 text-sm font-medium"
                  >
                    {link.label}
                  </a>
                ))}
                <Button className="mt-2">Sign up</Button>
              </nav>
            </SheetContent>
          </Sheet>
        </div>
      </header>
    </div>
  )
}
```

---

### Mega menu

A wide, multi-column mega-menu dropdown — grouped link sections under one trigger.

**Install:**

```bash
npx shadcn@latest add @designrevision/navigation-menu-mega-01
```

**Dependencies:** navigation-menu

```tsx
// components/ui/navigation-menu-mega-01.tsx
import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
} from "@/components/ui/navigation-menu"

const sections = [
  {
    heading: "Marketing",
    items: ["Landing pages", "SEO tools", "Email campaigns", "Analytics"],
  },
  {
    heading: "Sales",
    items: ["CRM", "Pipeline", "Forecasting", "Quotes"],
  },
  {
    heading: "Support",
    items: ["Help desk", "Live chat", "Knowledge base", "Community"],
  },
]

export default function NavigationMenuMega01() {
  return (
    <NavigationMenu>
      <NavigationMenuList>
        <NavigationMenuItem>
          <NavigationMenuTrigger>Solutions</NavigationMenuTrigger>
          <NavigationMenuContent>
            <div className="grid w-[600px] grid-cols-3 gap-4 p-4">
              {sections.map((section) => (
                <div key={section.heading}>
                  <p className="text-muted-foreground mb-2 px-2 text-xs font-medium uppercase">
                    {section.heading}
                  </p>
                  <ul className="space-y-1">
                    {section.items.map((item) => (
                      <li key={item}>
                        <NavigationMenuLink asChild>
                          <a
                            href="#"
                            className="hover:bg-accent block rounded-md px-2 py-1.5 text-sm"
                          >
                            {item}
                          </a>
                        </NavigationMenuLink>
                      </li>
                    ))}
                  </ul>
                </div>
              ))}
            </div>
          </NavigationMenuContent>
        </NavigationMenuItem>
      </NavigationMenuList>
    </NavigationMenu>
  )
}
```

---

### Active link

Highlighting the current route — the `active` prop sets `data-active` on the matching link.

**Install:**

```bash
npx shadcn@latest add @designrevision/navigation-menu-active-01
```

**Dependencies:** navigation-menu

```tsx
// components/ui/navigation-menu-active-01.tsx
import {
  NavigationMenu,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  navigationMenuTriggerStyle,
} from "@/components/ui/navigation-menu"

const links = [
  { label: "Dashboard", href: "#" },
  { label: "Projects", href: "#" },
  { label: "Team", href: "#" },
  { label: "Settings", href: "#" },
]

// In a real app this comes from the router (usePathname).
const activeLabel = "Dashboard"

export default function NavigationMenuActive01() {
  return (
    <NavigationMenu>
      <NavigationMenuList>
        {links.map((link) => (
          <NavigationMenuItem key={link.label}>
            <NavigationMenuLink
              asChild
              active={link.label === activeLabel}
              className={navigationMenuTriggerStyle()}
            >
              <a href={link.href}>{link.label}</a>
            </NavigationMenuLink>
          </NavigationMenuItem>
        ))}
      </NavigationMenuList>
    </NavigationMenu>
  )
}
```
