Getting Started
Components
- Accordion
- Alert
- Alert Dialog
- Avatar
- Badge
- Button
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Circular Progress
- Collapsible
- Compare Slider
- Dialog
- Dropdown Menu
- Gauge
- Input
- Label
- Marquee
- Navigation Menu
- Number Field
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Tooltip
Demos
Two menus with panels and a plain link.
"use client"
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle,
} from "@workspace/ui/components/navigation-menu"
const tests = [
{ title: "Full panel", href: "#", description: "40 biomarkers across every body system." },
{ title: "Heart health", href: "#", description: "Lipids, inflammation and blood pressure." },
{ title: "Hormones", href: "#", description: "Thyroid, cortisol and sex hormones." },
{ title: "Metabolic", href: "#", description: "Glucose, insulin and HbA1c." },
]
const guides = [
{ title: "Preparing for a test", href: "#", description: "Fasting, hydration and what to bring." },
{ title: "Reading your results", href: "#", description: "What healthy ranges mean for you." },
{ title: "Retesting", href: "#", description: "How often to test and why it matters." },
]
export function NavigationMenuDemo() {
return (
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Tests</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-80 grid-cols-2 gap-1">
{tests.map((item) => (
<ListItem key={item.title} {...item} />
))}
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuTrigger>Guides</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-60 gap-1">
{guides.map((item) => (
<ListItem key={item.title} {...item} />
))}
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="#" className={navigationMenuTriggerStyle()}>
Pricing
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
)
}
function ListItem({
title,
href,
description,
}: {
title: string
href: string
description: string
}) {
return (
<li>
<NavigationMenuLink href={href} className="flex-col items-start gap-1">
<span className="font-medium">{title}</span>
<span className="line-clamp-2 text-muted-foreground">{description}</span>
</NavigationMenuLink>
</li>
)
}
Usage
Use a navigation menu for the main links of a site header. Each item is either a trigger that opens a panel of links, or a link on its own. For actions on the current page, such as an account menu with "Sign out", use a dropdown menu.
Import it from @workspace/ui/components/navigation-menu.
Anatomy
- NavigationMenu — The root. Renders a
navand the shared popup that holds every panel. - NavigationMenuList — The row of items.
- NavigationMenuItem — One item in the row.
- NavigationMenuTrigger — Opens the item's panel on hover, focus or click. Shows a chevron that turns when open.
- NavigationMenuContent — The panel. Its contents move into the shared popup, which resizes between panels.
- NavigationMenuLink — A link, inside a panel or on its own in the row.
- navigationMenuTriggerStyle — Classes that make a NavigationMenuLink in the row match the triggers.
Notes
- Give each panel a width, for example
w-72on the list inside NavigationMenuContent. The popup sizes itself to the open panel. - To use a router link such as
next/link, pass it torender:<NavigationMenuLink render={<Link href="/pricing" />}>Pricing</NavigationMenuLink>. - Set
activeon the link for the current page. It setsaria-current="page"anddata-activefor styling. - The menu does not collapse on small screens. Hide it below a breakpoint and show the links in a sheet instead, as the header block does.
Examples
With icon
Put an icon before the label. Icons are sized to size-4 unless you set a size.
"use client"
import { CalendarIcon, FileTextIcon, HeartPulseIcon, SettingsIcon } from "lucide-react"
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from "@workspace/ui/components/navigation-menu"
export function NavigationMenuWithIcon() {
return (
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Account</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-48">
<li>
<NavigationMenuLink href="#">
<HeartPulseIcon />
Biomarkers
</NavigationMenuLink>
</li>
<li>
<NavigationMenuLink href="#">
<FileTextIcon />
Reports
</NavigationMenuLink>
</li>
<li>
<NavigationMenuLink href="#">
<CalendarIcon />
Bookings
</NavigationMenuLink>
</li>
<li>
<NavigationMenuLink href="#">
<SettingsIcon />
Settings
</NavigationMenuLink>
</li>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
)
}
Links
Links on their own, with no panels. The first link is active.
"use client"
import {
NavigationMenu,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
navigationMenuTriggerStyle,
} from "@workspace/ui/components/navigation-menu"
const links = ["How it works", "Pricing", "Clinics"]
export function NavigationMenuLinks() {
return (
<NavigationMenu>
<NavigationMenuList>
{links.map((link, index) => (
<NavigationMenuItem key={link}>
<NavigationMenuLink
href="#"
active={index === 0}
className={navigationMenuTriggerStyle()}
>
{link}
</NavigationMenuLink>
</NavigationMenuItem>
))}
</NavigationMenuList>
</NavigationMenu>
)
}
Props
These are the props you set most often. Unlisted props pass through to the underlying Base UI part.
NavigationMenu
| Prop | Type | Default | Description |
|---|---|---|---|
align | "start" or "center" or "end" | "start" | How the popup lines up with the open trigger. |
value | any | — | Value of the open item, when controlled. |
defaultValue | any | null | Value of the item open at first. |
onValueChange | (value) => void | — | Called when an item opens or closes. |
delay | number | 50 | Milliseconds of hover before a panel opens. |
closeDelay | number | 50 | Milliseconds before a panel closes after the pointer leaves. |
className | string | — | Classes merged onto the root. |
NavigationMenuLink
| Prop | Type | Default | Description |
|---|---|---|---|
href | string | — | Where the link goes. |
active | boolean | false | Whether the link is the current page. |
closeOnClick | boolean | false | Whether clicking closes the menu. |
render | ReactElement | — | Element to render instead of a, such as a router link. |