Shadcn Navigation Menu
React navigation menu component for website navigation with dropdowns and mega menus. Built with TypeScript and Tailwind CSS for Next.js using Radix UI.
Nav menu not responsive?
Join our Discord community for help from other developers.
Ever built a website where users couldn't find anything because your navigation was a mess? Or tried to cram dozens of links into a tiny dropdown that nobody wanted to use? Yeah, that's exactly when you need a proper navigation menu. This shadcn/ui navigation menu brings that smooth, professional navigation experience to your React applications.
Navigation menu showcase
Complete navigation with organized content sections:
"use client"import * as React from "react"import Link from "next/link"import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, navigationMenuTriggerStyle,} from "@/components/ui/navigation-menu"const components: { title: string; href: string; description: string }[] = [ { title: "Alert Dialog", href: "#", description: "A modal dialog that interrupts the user with important content and expects a response.", }, { title: "Hover Card", href: "#", description: "For sighted users to preview content available behind a link.", }, { title: "Progress", href: "#", description: "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", }, { title: "Scroll-area", href: "#", description: "Visually or semantically separates content.", }, { title: "Tabs", href: "#", description: "A set of layered sections of content—known as tab panels—that are displayed one at a time.", }, { title: "Tooltip", href: "#", description: "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", },]export default function NavigationMenuDemo() { return ( <div className="flex justify-center self-start pt-6 w-full" style={{ all: 'revert', display: 'flex', justifyContent: 'center', alignSelf: 'flex-start', paddingTop: '1.5rem', width: '100%', fontSize: '14px', lineHeight: '1.5', letterSpacing: 'normal' }} > <NavigationMenu> <NavigationMenuList> <NavigationMenuItem> <NavigationMenuTrigger>Getting started</NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr] list-none"> <li className="row-span-3"> <NavigationMenuLink asChild> <a className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md" href="#" onClick={(e) => e.preventDefault()} > <div className="mb-2 mt-4 text-lg font-medium"> shadcn/ui </div> <p className="text-sm leading-tight text-muted-foreground"> Beautifully designed components built with Radix UI and 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...etc </ListItem> </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuTrigger>Components</NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] list-none"> {components.map((component) => ( <ListItem key={component.title} title={component.title} href={component.href} > {component.description} </ListItem> ))} </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuLink asChild> <Link href="#" className={navigationMenuTriggerStyle()} onClick={(e) => e.preventDefault()}> Documentation </Link> </NavigationMenuLink> </NavigationMenuItem> </NavigationMenuList> </NavigationMenu> </div> )}const ListItem = React.forwardRef< React.ElementRef<"a">, React.ComponentPropsWithoutRef<"a">>(({ className, title, children, ...props }, ref) => { return ( <li> <NavigationMenuLink asChild> <a ref={ref} className="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground" onClick={(e) => e.preventDefault()} {...props} > <div className="text-sm font-medium leading-none">{title}</div> <p className="line-clamp-2 text-sm leading-snug text-muted-foreground"> {children} </p> </a> </NavigationMenuLink> </li> )})ListItem.displayName = "ListItem"
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,}
Built on Radix UI NavigationMenu primitives with full keyboard navigation, hover delays, and all the accessibility features users expect from modern website navigation. Styled with Tailwind CSS so it matches your design system instead of looking like a generic system menu.
npx shadcn@latest add navigation-menu
Why navigation menus actually improve website usability
Here's the thing—regular dropdowns are fine for simple stuff, but modern websites need navigation that helps users discover content instead of hiding it. Think about how Stripe organizes their product pages, or how GitHub structures their documentation. You hover over a section and get organized previews of what's available.
Users expect navigation to be more than just a list of links. They want visual hierarchy, helpful descriptions, and logical grouping. A well-designed navigation menu reduces cognitive load and helps people find what they're looking for faster. That's the difference between navigation that works and navigation that gets in the way.
This free shadcn navigation menu handles the complex parts—hover timing, keyboard navigation, focus management, accessibility—while you focus on organizing your content. Whether you're building marketing sites, documentation, or SaaS applications in your Next.js projects, navigation that guides users keeps them engaged in your JavaScript applications.
Common navigation patterns you'll actually use
Simple horizontal menu
Clean navigation bar for straightforward sites:
"use client"import * as React from "react"import Link from "next/link"import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, navigationMenuTriggerStyle,} from "@/components/ui/navigation-menu"const components: { title: string; href: string; description: string }[] = [ { title: "Alert Dialog", href: "#", description: "A modal dialog that interrupts the user with important content and expects a response.", }, { title: "Hover Card", href: "#", description: "For sighted users to preview content available behind a link.", }, { title: "Progress", href: "#", description: "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", }, { title: "Scroll-area", href: "#", description: "Visually or semantically separates content.", }, { title: "Tabs", href: "#", description: "A set of layered sections of content—known as tab panels—that are displayed one at a time.", }, { title: "Tooltip", href: "#", description: "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", },]export default function NavigationMenuDemo() { return ( <div className="flex justify-center self-start pt-6 w-full" style={{ all: 'revert', display: 'flex', justifyContent: 'center', alignSelf: 'flex-start', paddingTop: '1.5rem', width: '100%', fontSize: '14px', lineHeight: '1.5', letterSpacing: 'normal' }} > <NavigationMenu> <NavigationMenuList> <NavigationMenuItem> <NavigationMenuTrigger>Getting started</NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr] list-none"> <li className="row-span-3"> <NavigationMenuLink asChild> <a className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md" href="#" onClick={(e) => e.preventDefault()} > <div className="mb-2 mt-4 text-lg font-medium"> shadcn/ui </div> <p className="text-sm leading-tight text-muted-foreground"> Beautifully designed components built with Radix UI and 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...etc </ListItem> </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuTrigger>Components</NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] list-none"> {components.map((component) => ( <ListItem key={component.title} title={component.title} href={component.href} > {component.description} </ListItem> ))} </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuLink asChild> <Link href="#" className={navigationMenuTriggerStyle()} onClick={(e) => e.preventDefault()}> Documentation </Link> </NavigationMenuLink> </NavigationMenuItem> </NavigationMenuList> </NavigationMenu> </div> )}const ListItem = React.forwardRef< React.ElementRef<"a">, React.ComponentPropsWithoutRef<"a">>(({ className, title, children, ...props }, ref) => { return ( <li> <NavigationMenuLink asChild> <a ref={ref} className="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground" onClick={(e) => e.preventDefault()} {...props} > <div className="text-sm font-medium leading-none">{title}</div> <p className="line-clamp-2 text-sm leading-snug text-muted-foreground"> {children} </p> </a> </NavigationMenuLink> </li> )})ListItem.displayName = "ListItem"
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,}
Mega menu with sections
Organized content sections for complex sites:
"use client"import * as React from "react"import Link from "next/link"import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, navigationMenuTriggerStyle,} from "@/components/ui/navigation-menu"const components: { title: string; href: string; description: string }[] = [ { title: "Alert Dialog", href: "#", description: "A modal dialog that interrupts the user with important content and expects a response.", }, { title: "Hover Card", href: "#", description: "For sighted users to preview content available behind a link.", }, { title: "Progress", href: "#", description: "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", }, { title: "Scroll-area", href: "#", description: "Visually or semantically separates content.", }, { title: "Tabs", href: "#", description: "A set of layered sections of content—known as tab panels—that are displayed one at a time.", }, { title: "Tooltip", href: "#", description: "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", },]export default function NavigationMenuDemo() { return ( <div className="flex justify-center self-start pt-6 w-full" style={{ all: 'revert', display: 'flex', justifyContent: 'center', alignSelf: 'flex-start', paddingTop: '1.5rem', width: '100%', fontSize: '14px', lineHeight: '1.5', letterSpacing: 'normal' }} > <NavigationMenu> <NavigationMenuList> <NavigationMenuItem> <NavigationMenuTrigger>Getting started</NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr] list-none"> <li className="row-span-3"> <NavigationMenuLink asChild> <a className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md" href="#" onClick={(e) => e.preventDefault()} > <div className="mb-2 mt-4 text-lg font-medium"> shadcn/ui </div> <p className="text-sm leading-tight text-muted-foreground"> Beautifully designed components built with Radix UI and 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...etc </ListItem> </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuTrigger>Components</NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] list-none"> {components.map((component) => ( <ListItem key={component.title} title={component.title} href={component.href} > {component.description} </ListItem> ))} </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuLink asChild> <Link href="#" className={navigationMenuTriggerStyle()} onClick={(e) => e.preventDefault()}> Documentation </Link> </NavigationMenuLink> </NavigationMenuItem> </NavigationMenuList> </NavigationMenu> </div> )}const ListItem = React.forwardRef< React.ElementRef<"a">, React.ComponentPropsWithoutRef<"a">>(({ className, title, children, ...props }, ref) => { return ( <li> <NavigationMenuLink asChild> <a ref={ref} className="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground" onClick={(e) => e.preventDefault()} {...props} > <div className="text-sm font-medium leading-none">{title}</div> <p className="line-clamp-2 text-sm leading-snug text-muted-foreground"> {children} </p> </a> </NavigationMenuLink> </li> )})ListItem.displayName = "ListItem"
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,}
Documentation navigation
Structured navigation perfect for docs sites:
"use client"import * as React from "react"import Link from "next/link"import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, navigationMenuTriggerStyle,} from "@/components/ui/navigation-menu"const components: { title: string; href: string; description: string }[] = [ { title: "Alert Dialog", href: "#", description: "A modal dialog that interrupts the user with important content and expects a response.", }, { title: "Hover Card", href: "#", description: "For sighted users to preview content available behind a link.", }, { title: "Progress", href: "#", description: "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", }, { title: "Scroll-area", href: "#", description: "Visually or semantically separates content.", }, { title: "Tabs", href: "#", description: "A set of layered sections of content—known as tab panels—that are displayed one at a time.", }, { title: "Tooltip", href: "#", description: "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", },]export default function NavigationMenuDemo() { return ( <div className="flex justify-center self-start pt-6 w-full" style={{ all: 'revert', display: 'flex', justifyContent: 'center', alignSelf: 'flex-start', paddingTop: '1.5rem', width: '100%', fontSize: '14px', lineHeight: '1.5', letterSpacing: 'normal' }} > <NavigationMenu> <NavigationMenuList> <NavigationMenuItem> <NavigationMenuTrigger>Getting started</NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr] list-none"> <li className="row-span-3"> <NavigationMenuLink asChild> <a className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md" href="#" onClick={(e) => e.preventDefault()} > <div className="mb-2 mt-4 text-lg font-medium"> shadcn/ui </div> <p className="text-sm leading-tight text-muted-foreground"> Beautifully designed components built with Radix UI and 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...etc </ListItem> </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuTrigger>Components</NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] list-none"> {components.map((component) => ( <ListItem key={component.title} title={component.title} href={component.href} > {component.description} </ListItem> ))} </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuLink asChild> <Link href="#" className={navigationMenuTriggerStyle()} onClick={(e) => e.preventDefault()}> Documentation </Link> </NavigationMenuLink> </NavigationMenuItem> </NavigationMenuList> </NavigationMenu> </div> )}const ListItem = React.forwardRef< React.ElementRef<"a">, React.ComponentPropsWithoutRef<"a">>(({ className, title, children, ...props }, ref) => { return ( <li> <NavigationMenuLink asChild> <a ref={ref} className="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground" onClick={(e) => e.preventDefault()} {...props} > <div className="text-sm font-medium leading-none">{title}</div> <p className="line-clamp-2 text-sm leading-snug text-muted-foreground"> {children} </p> </a> </NavigationMenuLink> </li> )})ListItem.displayName = "ListItem"
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,}
E-commerce navigation
Product categories with visual organization:
"use client"import * as React from "react"import Link from "next/link"import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, navigationMenuTriggerStyle,} from "@/components/ui/navigation-menu"const components: { title: string; href: string; description: string }[] = [ { title: "Alert Dialog", href: "#", description: "A modal dialog that interrupts the user with important content and expects a response.", }, { title: "Hover Card", href: "#", description: "For sighted users to preview content available behind a link.", }, { title: "Progress", href: "#", description: "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", }, { title: "Scroll-area", href: "#", description: "Visually or semantically separates content.", }, { title: "Tabs", href: "#", description: "A set of layered sections of content—known as tab panels—that are displayed one at a time.", }, { title: "Tooltip", href: "#", description: "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", },]export default function NavigationMenuDemo() { return ( <div className="flex justify-center self-start pt-6 w-full" style={{ all: 'revert', display: 'flex', justifyContent: 'center', alignSelf: 'flex-start', paddingTop: '1.5rem', width: '100%', fontSize: '14px', lineHeight: '1.5', letterSpacing: 'normal' }} > <NavigationMenu> <NavigationMenuList> <NavigationMenuItem> <NavigationMenuTrigger>Getting started</NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr] list-none"> <li className="row-span-3"> <NavigationMenuLink asChild> <a className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md" href="#" onClick={(e) => e.preventDefault()} > <div className="mb-2 mt-4 text-lg font-medium"> shadcn/ui </div> <p className="text-sm leading-tight text-muted-foreground"> Beautifully designed components built with Radix UI and 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...etc </ListItem> </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuTrigger>Components</NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] list-none"> {components.map((component) => ( <ListItem key={component.title} title={component.title} href={component.href} > {component.description} </ListItem> ))} </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuLink asChild> <Link href="#" className={navigationMenuTriggerStyle()} onClick={(e) => e.preventDefault()}> Documentation </Link> </NavigationMenuLink> </NavigationMenuItem> </NavigationMenuList> </NavigationMenu> </div> )}const ListItem = React.forwardRef< React.ElementRef<"a">, React.ComponentPropsWithoutRef<"a">>(({ className, title, children, ...props }, ref) => { return ( <li> <NavigationMenuLink asChild> <a ref={ref} className="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground" onClick={(e) => e.preventDefault()} {...props} > <div className="text-sm font-medium leading-none">{title}</div> <p className="line-clamp-2 text-sm leading-snug text-muted-foreground"> {children} </p> </a> </NavigationMenuLink> </li> )})ListItem.displayName = "ListItem"
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,}
Multi-level dropdown
Nested navigation for hierarchical content:
"use client"import * as React from "react"import Link from "next/link"import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, navigationMenuTriggerStyle,} from "@/components/ui/navigation-menu"const components: { title: string; href: string; description: string }[] = [ { title: "Alert Dialog", href: "#", description: "A modal dialog that interrupts the user with important content and expects a response.", }, { title: "Hover Card", href: "#", description: "For sighted users to preview content available behind a link.", }, { title: "Progress", href: "#", description: "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", }, { title: "Scroll-area", href: "#", description: "Visually or semantically separates content.", }, { title: "Tabs", href: "#", description: "A set of layered sections of content—known as tab panels—that are displayed one at a time.", }, { title: "Tooltip", href: "#", description: "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", },]export default function NavigationMenuDemo() { return ( <div className="flex justify-center self-start pt-6 w-full" style={{ all: 'revert', display: 'flex', justifyContent: 'center', alignSelf: 'flex-start', paddingTop: '1.5rem', width: '100%', fontSize: '14px', lineHeight: '1.5', letterSpacing: 'normal' }} > <NavigationMenu> <NavigationMenuList> <NavigationMenuItem> <NavigationMenuTrigger>Getting started</NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr] list-none"> <li className="row-span-3"> <NavigationMenuLink asChild> <a className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md" href="#" onClick={(e) => e.preventDefault()} > <div className="mb-2 mt-4 text-lg font-medium"> shadcn/ui </div> <p className="text-sm leading-tight text-muted-foreground"> Beautifully designed components built with Radix UI and 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...etc </ListItem> </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuTrigger>Components</NavigationMenuTrigger> <NavigationMenuContent> <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] list-none"> {components.map((component) => ( <ListItem key={component.title} title={component.title} href={component.href} > {component.description} </ListItem> ))} </ul> </NavigationMenuContent> </NavigationMenuItem> <NavigationMenuItem> <NavigationMenuLink asChild> <Link href="#" className={navigationMenuTriggerStyle()} onClick={(e) => e.preventDefault()}> Documentation </Link> </NavigationMenuLink> </NavigationMenuItem> </NavigationMenuList> </NavigationMenu> </div> )}const ListItem = React.forwardRef< React.ElementRef<"a">, React.ComponentPropsWithoutRef<"a">>(({ className, title, children, ...props }, ref) => { return ( <li> <NavigationMenuLink asChild> <a ref={ref} className="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground" onClick={(e) => e.preventDefault()} {...props} > <div className="text-sm font-medium leading-none">{title}</div> <p className="line-clamp-2 text-sm leading-snug text-muted-foreground"> {children} </p> </a> </NavigationMenuLink> </li> )})ListItem.displayName = "ListItem"
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,}
Features
This free open source navigation menu component includes everything you need:
- TypeScript-first - Full type safety with navigation events and state management
- Radix UI powered - Battle-tested accessibility and keyboard navigation
- Smooth interactions - Smart hover delays and animations that feel natural
- Tailwind CSS styled - Customize with utilities, not fighting component CSS
- Keyboard accessible - Arrow keys, Tab navigation, Escape to close
- Mobile responsive - Touch-optimized interactions for all devices
- Rich content support - Icons, descriptions, featured content in dropdowns
- Animation ready - CSS variables and data attributes for custom animations
API Reference
Core Components
Component | Purpose | Key Props |
---|---|---|
NavigationMenu | Root container | orientation for layout direction |
NavigationMenuList | Menu items container | Groups all navigation items |
NavigationMenuItem | Individual menu item | Contains trigger and content |
NavigationMenuTrigger | Clickable menu button | Opens dropdown content |
NavigationMenuContent | Dropdown panel | Contains organized links and content |
Navigation Elements
Component | Purpose | Use Case |
---|---|---|
NavigationMenuLink | Styled link wrapper | Individual navigation links |
NavigationMenuIndicator | Visual indicator | Shows active menu item |
NavigationMenuViewport | Content container | Handles positioning and animations |
Helper Functions
Function | Purpose | Usage |
---|---|---|
navigationMenuTriggerStyle() | Pre-styled classes | Consistent trigger appearance |
CSS Variables | Animation support | Width/height for smooth transitions |
Production tips
Organize content logically with visual hierarchy. This free shadcn/ui navigation menu supports rich content—use it wisely. Group related links together, add helpful descriptions, and highlight important sections. This TypeScript component provides the structure—you provide the organization that matches user mental models in your Next.js applications.
Time hover interactions carefully. The component includes smart hover delays to prevent accidental triggers, but test with real users. This open source shadcn navigation adapts to different interaction patterns—find timing that feels natural for your audience.
Design for mobile from the start. Navigation menus work on touch devices, but consider alternative patterns like Sheet or Drawer components for mobile-first experiences. This JavaScript component is responsive, but mobile users often prefer different navigation patterns.
Keep content scannable and actionable. Don't overwhelm users with too many options in dropdown content. This Tailwind CSS styled component supports complex layouts, but restraint creates better user experiences. Focus on helping users find what they need quickly.
Test keyboard navigation thoroughly. The component handles focus management automatically, but test the complete flow with real keyboard users. Screen readers need logical content organization and clear labels to announce navigation structure properly.
Integration with other components
Navigation menus naturally work with Button components for consistent styling and Sheet components for mobile navigation in your React applications. Use Separator components to organize complex dropdown content visually.
For marketing sites, combine navigation with Card components for featured content sections or Badge components to highlight new features or popular pages. This open source pattern creates cohesive website experiences.
When building documentation sites, pair navigation menus with Breadcrumb components for hierarchical navigation or ScrollArea components for long content lists. The navigation provides top-level structure—other shadcn components handle specific content areas.
For dynamic content, use navigation menus with Avatar components for user account sections or DropdownMenu components for user actions. Your JavaScript application can compose these components while maintaining consistent navigation patterns.
Questions you might have
Shadcn Menubar
React menubar for desktop-style menu bars with keyboard shortcuts. Built with TypeScript and Tailwind CSS for Next.js using Radix UI.
Shadcn Pagination
React pagination for splitting large datasets across pages with navigation controls. Built with TypeScript and Tailwind CSS for Next.js.