Components
A collection of links for navigating websites.
Playground
asChild and stack a title over a description with a column wrapper inside the link.import Link from "next/link"
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from "@workspace/ui/components/navigation-menu"
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-72 gap-1">
<li>
<NavigationMenuLink asChild>
<Link href="/docs">
<div className="flex flex-col gap-1 text-sm">
<div className="leading-none font-medium">Introduction</div>
<div className="line-clamp-2 text-muted-foreground">
What the design system is and how it fits Westy.
</div>
</div>
</Link>
</NavigationMenuLink>
</li>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>asChild. Mark the current page with data-active for the muted highlight; the active prop additionally exposes aria-current="page".import Link from "next/link"
import {
NavigationMenuLink,
navigationMenuTriggerStyle,
} from "@workspace/ui/components/navigation-menu"
<NavigationMenuItem>
<NavigationMenuLink
asChild
active={pathname === "/docs"}
data-active={pathname === "/docs" || undefined}
className={navigationMenuTriggerStyle()}
>
<Link href="/docs">Docs</Link>
</NavigationMenuLink>
</NavigationMenuItem>viewport={false} to drop the shared viewport: each content panel becomes its own popover positioned under its trigger instead of sliding inside one centered surface. Use it when triggers sit far apart and the centered viewport would detach the panel from the trigger that opened it.<NavigationMenu viewport={false}>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Products</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-64 gap-1">
<li>
<NavigationMenuLink href="#">Components</NavigationMenuLink>
</li>
<li>
<NavigationMenuLink href="#">Charts</NavigationMenuLink>
</li>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>import { RocketLaunchIcon } from "@phosphor-icons/react"
<NavigationMenuContent>
<ul className="grid w-72 gap-1">
<li>
<NavigationMenuLink asChild>
<Link href="/docs">
<div className="flex flex-col gap-1 text-sm">
<div className="flex items-center gap-2 leading-none font-medium">
<RocketLaunchIcon />
Getting started
</div>
<div className="line-clamp-2 text-muted-foreground">
Install the package and render your first component.
</div>
</div>
</Link>
</NavigationMenuLink>
</li>
</ul>
</NavigationMenuContent>dir prop (or a surrounding Direction provider) — a plain dir="rtl" ancestor is not enough for the keyboard navigation and slide animations to flip. Styling follows via logical properties: the trigger caret keeps its position with ms-1, and the viewport anchors to the start edge.<NavigationMenu dir="rtl">
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>البدء</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-72 gap-1">
<li>
<NavigationMenuLink href="#">مقدمة</NavigationMenuLink>
</li>
<li>
<NavigationMenuLink href="#">التثبيت</NavigationMenuLink>
</li>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="#" className={navigationMenuTriggerStyle()}>
الوثائق
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu><nav> landmark with a list, and content holds plain links — so it deliberately avoids the ARIA menu roles, which are reserved for application menus. Triggers are buttons exposing aria-expanded and aria-controls; menus open on hover, focus, Enter or Space, arrow keys move within the bar and panels, and Escape closes and returns focus to the trigger. An active link exposes aria-current="page".<nav aria-label="Main" data-orientation="horizontal">
<ul>
<li>
<button aria-expanded="true" aria-controls="radix-:r1:">Products</button>
<div id="radix-:r1:"> <!-- content panel -->
<a href="/components">Components</a>
</div>
</li>
<li>
<a href="/docs" aria-current="page">Docs</a>
</li>
</ul>
</nav>| Component | Prop | Default |
|---|---|---|
| NavigationMenu | viewport?: boolean | true |
| NavigationMenu | dir?: "ltr" | "rtl" | inherited |
| NavigationMenu | delayDuration?: number | 200 |
| NavigationMenu | skipDelayDuration?: number | 300 |
| NavigationMenu | value?: string, onValueChange?: (value: string) => void | — |
| NavigationMenuItem | value?: string | — |
| NavigationMenuLink | active?: boolean | false |
| NavigationMenuLink | asChild?: boolean | false |
| NavigationMenuLink | onSelect?: (event: Event) => void | — |
<NavigationMenu data-slot="navigation-menu" /> // <nav>, renders the viewport <NavigationMenuList data-slot="navigation-menu-list" /> // <ul> <NavigationMenuItem data-slot="navigation-menu-item" /> // <li> <NavigationMenuTrigger data-slot="navigation-menu-trigger" /> // <button aria-expanded> + caret <NavigationMenuContent data-slot="navigation-menu-content" /> // panel inside the viewport <NavigationMenuLink data-slot="navigation-menu-link" /> // <a> <NavigationMenuIndicator data-slot="navigation-menu-indicator" /> // arrow under the trigger <NavigationMenuViewport data-slot="navigation-menu-viewport" /> // shared popover surface navigationMenuTriggerStyle() // cva helper — trigger look for plain links
Tokens used
11 design tokens consumed by the Navigation Menu component.
--popover
Popover
--popover-foreground
Popover Foreground
--muted
Muted
--ring
Ring
--foreground
Foreground
--border
Border
--radius-lg
Radius 1× (10px)
--radius-md
Radius 0.8× (8px)
--radius-sm
Radius 0.6× (6px)
--text-sm
Text Small (14px)
--spacing
Spacing unit (4px)