Navigation Menu
A collection of links for navigating websites.
'use client'
import * as React from 'react'
import Link from 'next/link'
import { buttonVariants, cn } from 'ui'
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle,
} from 'ui'
const components: { title: string; href: string; description: string }[] = [
{
title: 'Alert Dialog',
href: '/docs/primitives/alert-dialog',
description:
'A modal dialog that interrupts the user with important content and expects a response.',
},
{
title: 'Hover Card',
href: '/docs/primitives/hover-card',
description: 'For sighted users to preview content available behind a link.',
},
{
title: 'Progress',
href: '/docs/primitives/progress',
description:
'Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.',
},
{
title: 'Scroll-area',
href: '/docs/primitives/scroll-area',
description: 'Visually or semantically separates content.',
},
{
title: 'Tabs',
href: '/docs/primitives/tabs',
description:
'A set of layered sections of content—known as tab panels—that are displayed one at a time.',
},
{
title: 'Tooltip',
href: '/docs/primitives/tooltip',
description:
'A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.',
},
]
export function NavigationMenuDemo() {
return (
<div>
<NavigationMenu className="w-fit">
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger className={cn(buttonVariants({ type: 'text', size: 'small' }))}>
Getting started
</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
<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 border from-background-surface-100/20 to-background-surface-100 p-6 no-underline outline-none focus:shadow-md"
href="/"
>
{/* <Icons.logo className="h-6 w-6" /> */}
<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 that you can copy and paste into your apps.
Accessible. Customizable. Open Source.
</p>
</a>
</NavigationMenuLink>
</li>
<ListItem href="/docs" title="Introduction">
Re-usable components built using Radix UI and Tailwind CSS.
</ListItem>
<ListItem href="/docs/installation" title="Installation">
How to install dependencies and structure your app.
</ListItem>
<ListItem href="/docs/primitives/typography" title="Typography">
Styles for headings, paragraphs, lists...etc
</ListItem>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuTrigger className={cn(buttonVariants({ type: 'text', size: 'small' }))}>
Components
</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] ">
{components.map((component) => (
<ListItem key={component.title} title={component.title} href={component.href}>
{component.description}
</ListItem>
))}
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<Link href="/docs" legacyBehavior passHref>
<NavigationMenuLink className={buttonVariants({ type: 'text', size: 'small' })}>
Documentation
</NavigationMenuLink>
</Link>
</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={cn(
'block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-surface-100/50 hover:text-foreground focus:bg-surface-100/50 focus:text-foreground',
className
)}
{...props}
>
<div className="text-sm text-foreground leading-none">{title}</div>
<p className="line-clamp-2 text-sm leading-snug text-foreground-lighter">{children}</p>
</a>
</NavigationMenuLink>
</li>
)
}
)
ListItem.displayName = 'ListItem'
Installation
npx shadcn-ui@latest add navigation-menu
Usage
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuIndicator,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
NavigationMenuViewport,
} from '@/components/ui/navigation-menu'
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Item One</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuLink>Link</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
Examples
Link Component
When using the Next.js <Link />
component, you can use navigationMenuTriggerStyle()
to apply the correct styles to the trigger.
import { navigationMenuTriggerStyle } from '@/components/ui/navigation-menu'
<NavigationMenuItem>
<Link href="/docs" legacyBehavior passHref>
<NavigationMenuLink className={navigationMenuTriggerStyle()}>Documentation</NavigationMenuLink>
</Link>
</NavigationMenuItem>
See also the Radix UI documentation for handling client side routing.
With horizontal scroll
We can wrap a the <NavigationMenuList />
in a <ScrollArea />
component to make the menu scroll.
However, then we must also make sure the <NavigationMenuContent />
is positioned correctly and rendered outside the scroll area.
We set renderViewport={false}
on the <NavigationMenu />
component to prevent the viewport from being rendered.
And then add our own Viewport with <NavigationMenuViewport />
.
Then all our content panels will render themselves outside the scroll area and inside the viewport.
You can also add props to <NavigationMenuViewport />
to style it as you like, including the containerProps
prop to add classes to the container div element inside the viewport.
<NavigationMenu renderViewport={false}>
<ScrollArea>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Item One</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuLink>Link</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
<ScrollBar />
</ScrollArea>
<NavigationMenuViewport containerProps={{ className: 'w-full' }} />
</NavigationMenu>