1/** biome-ignore-all lint/a11y/useValidAnchor: demo */2"use client";3
4import {5 NavigationMenu,6 NavigationMenuContent,7 NavigationMenuItem,8 NavigationMenuLink,9 NavigationMenuList,10 NavigationMenuTrigger,11 navigationMenuTriggerStyle,12} from "@/components/ui/pxl/navigation-menu";13
14const components: { title: string; href: string; description: string }[] = [15 {16 title: "Alert Dialog",17 href: "/docs/primitives/alert-dialog",18 description:19 "A modal dialog that interrupts the user with important content and expects a response.",20 },21 {22 title: "Hover Card",23 href: "/docs/primitives/hover-card",24 description:25 "For sighted users to preview content available behind a link.",26 },27 {28 title: "Progress",29 href: "/docs/primitives/progress",30 description:31 "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.",32 },33 {34 title: "Scroll-area",35 href: "/docs/primitives/scroll-area",36 description: "Visually or semantically separates content.",37 },38 {39 title: "Tabs",40 href: "/docs/primitives/tabs",41 description:42 "A set of layered sections of content—known as tab panels—that are displayed one at a time.",43 },44 {45 title: "Tooltip",46 href: "/docs/primitives/tooltip",47 description:48 "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.",49 },50];51
52function ListItem({53 title,54 children,55 href,56 ...props57}: React.ComponentPropsWithoutRef<"li"> & { href: string }) {58 return (59 <li {...props}>60 <NavigationMenuLink61 render={62 <a href={href}>63 <div className="flex flex-col gap-1 text-sm">64 <div className="leading-none font-medium">{title}</div>65 <div className="line-clamp-2 text-muted-foreground">66 {children}67 </div>68 </div>69 </a>70 }71 />72 </li>73 );74}75
76export default function NavigationMenuDemo() {77 return (78 <NavigationMenu>79 <NavigationMenuList>80 <NavigationMenuItem>81 <NavigationMenuTrigger>Getting started</NavigationMenuTrigger>82 <NavigationMenuContent>83 <ul className="w-96">84 <ListItem href="/docs" title="Introduction">85 Re-usable components built with Tailwind CSS.86 </ListItem>87 <ListItem href="/docs/installation" title="Installation">88 How to install dependencies and structure your app.89 </ListItem>90 <ListItem href="/docs/primitives/typography" title="Typography">91 Styles for headings, paragraphs, lists...etc92 </ListItem>93 </ul>94 </NavigationMenuContent>95 </NavigationMenuItem>96 <NavigationMenuItem className="hidden md:flex">97 <NavigationMenuTrigger>Components</NavigationMenuTrigger>98 <NavigationMenuContent>99 <ul className="grid w-100 gap-2 md:w-125 md:grid-cols-2 lg:w-150">100 {components.map((component) => (101 <ListItem102 key={component.title}103 title={component.title}104 href={component.href}105 >106 {component.description}107 </ListItem>108 ))}109 </ul>110 </NavigationMenuContent>111 </NavigationMenuItem>112 <NavigationMenuItem>113 <NavigationMenuTrigger>With Icon</NavigationMenuTrigger>114 <NavigationMenuContent>115 <ul className="grid w-50">116 <li>117 <NavigationMenuLink118 render={119 <a href="#" className="flex-row items-center gap-2">120 <svg121 xmlns="http://www.w3.org/2000/svg"122 fill="currentColor"123 viewBox="0 0 24 24"124 >125 <path d="M18 22H6v-2h12v2ZM6 20H4v-2h2v2Zm14 0h-2v-2h2v2ZM4 18H2V6h2v12Zm9 0h-2v-2h2v2Zm9 0h-2V6h2v12Zm-9-4h-2V6h2v8ZM6 6H4V4h2v2Zm14 0h-2V4h2v2Zm-2-2H6V2h12v2Z"></path>126 </svg>127 Backlog128 </a>129 }130 />131 <NavigationMenuLink132 render={133 <a href="#" className="flex-row items-center gap-2">134 <svg135 xmlns="http://www.w3.org/2000/svg"136 fill="currentColor"137 viewBox="0 0 24 24"138 >139 <path d="M18 22H6v-2h12v2ZM6 20H4v-2h2v2Zm14 0h-2v-2h2v2ZM4 18H2V6h2v12Zm18 0h-2V6h2v12ZM6 6H4V4h2v2Zm14 0h-2V4h2v2Zm-2-2H6V2h12v2Z" />140 </svg>141 To Do142 </a>143 }144 />145 <NavigationMenuLink146 render={147 <a href="#" className="flex-row items-center gap-2">148 <svg149 xmlns="http://www.w3.org/2000/svg"150 fill="currentColor"151 viewBox="0 0 24 24"152 >153 <path d="M18 22H6v-2h12v2ZM6 20H4v-2h2v2Zm14 0h-2v-2h2v2ZM4 18H2V6h2v12Zm18 0h-2V6h2v12Zm-11-2H9v-2h2v2Zm-2-2H7v-2h2v2Zm4 0h-2v-2h2v2Zm2-2h-2v-2h2v2Zm2-2h-2V8h2v2ZM6 6H4V4h2v2Zm14 0h-2V4h2v2Zm-2-2H6V2h12v2Z"></path>154 </svg>155 Done156 </a>157 }158 />159 </li>160 </ul>161 </NavigationMenuContent>162 </NavigationMenuItem>163 <NavigationMenuItem>164 <NavigationMenuLink165 className={navigationMenuTriggerStyle()}166 render={<a href="/docs">Docs</a>}167 />168 </NavigationMenuItem>169 </NavigationMenuList>170 </NavigationMenu>171 );172}Installation
Section titled “Installation”pnpm dlx shadcn@latest add pxl-ui/registry/navigation-menu
Copy and paste the following code into your project.
1import { NavigationMenu as NavigationMenuPrimitive } from "@base-ui/react/navigation-menu";2import { cva } from "class-variance-authority";3
4import { cn } from "@/lib/utils";5
6function NavigationMenu({7 align = "start",8 className,9 children,10 ...props11}: NavigationMenuPrimitive.Root.Props &12 Pick<NavigationMenuPrimitive.Positioner.Props, "align">) {13 return (14 <NavigationMenuPrimitive.Root15 data-slot="navigation-menu"16 className={cn(17 "group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",18 className,19 )}20 {...props}21 >22 {children}23 <NavigationMenuPositioner align={align} />24 </NavigationMenuPrimitive.Root>25 );26}27
28function NavigationMenuList({29 className,30 ...props31}: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.List>) {32 return (33 <NavigationMenuPrimitive.List34 data-slot="navigation-menu-list"35 className={cn(36 "group flex flex-1 list-none items-center justify-center gap-0",37 className,38 )}39 {...props}40 />41 );42}43
44function NavigationMenuItem({45 className,46 ...props47}: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.Item>) {48 return (49 <NavigationMenuPrimitive.Item50 data-slot="navigation-menu-item"51 className={cn("relative", className)}52 {...props}53 />54 );55}56
57const navigationMenuTriggerStyle = cva(58 "group/navigation-menu-trigger inline-flex h-9 w-max items-center justify-center pixel-rounded pixel-rounded-md px-2.5 py-1.5 text-sm font-medium transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-popup-open:bg-muted/50 data-popup-open:hover:bg-muted data-open:bg-muted/50 data-open:hover:bg-muted data-open:focus:bg-muted",59);60
61function NavigationMenuTrigger({62 className,63 children,64 ...props65}: NavigationMenuPrimitive.Trigger.Props) {66 return (67 <NavigationMenuPrimitive.Trigger68 data-slot="navigation-menu-trigger"69 className={cn(navigationMenuTriggerStyle(), "group", className)}70 {...props}71 >72 {children}{" "}73 <svg74 xmlns="http://www.w3.org/2000/svg"75 fill="currentColor"76 viewBox="0 0 24 24"77 className="relative top-px ml-1 size-3 transition duration-300 group-data-popup-open/navigation-menu-trigger:rotate-180 group-data-open/navigation-menu-trigger:rotate-180"78 aria-hidden="true"79 >80 <path d="M13 16h-2v-2h2v2Zm-2-2H9v-2h2v2Zm4 0h-2v-2h2v2Zm-6-2H7v-2h2v2Zm8 0h-2v-2h2v2ZM7 10H5V8h2v2Zm12 0h-2V8h2v2Z" />81 </svg>82 </NavigationMenuPrimitive.Trigger>83 );84}85
86function NavigationMenuContent({87 className,88 ...props89}: NavigationMenuPrimitive.Content.Props) {90 return (91 <NavigationMenuPrimitive.Content92 data-slot="navigation-menu-content"93 className={cn(94 "data-ending-style:data-activation-direction=left:translate-x-[50%] data-ending-style:data-activation-direction=right:translate-x-[-50%] data-starting-style:data-activation-direction=left:translate-x-[-50%] data-starting-style:data-activation-direction=right:translate-x-[50%] h-full w-auto p-[calc(var(--pixel-size)+(--spacing(1)))] transition-[opacity,transform,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] group-data-[viewport=false]/navigation-menu:pixel-rounded group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:ring-1 group-data-[viewport=false]/navigation-menu:ring-foreground/10 group-data-[viewport=false]/navigation-menu:duration-300 data-ending-style:opacity-0 data-starting-style:opacity-0 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 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none group-data-[viewport=false]/navigation-menu:data-open:animate-in group-data-[viewport=false]/navigation-menu:data-open:fade-in-0 group-data-[viewport=false]/navigation-menu:data-open:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-closed:animate-out group-data-[viewport=false]/navigation-menu:data-closed:fade-out-0 group-data-[viewport=false]/navigation-menu:data-closed:zoom-out-95",95 className,96 )}97 {...props}98 />99 );100}101
102function NavigationMenuPositioner({103 className,104 side = "bottom",105 sideOffset = 8,106 align = "start",107 alignOffset = 0,108 ...props109}: NavigationMenuPrimitive.Positioner.Props) {110 return (111 <NavigationMenuPrimitive.Portal>112 <NavigationMenuPrimitive.Positioner113 side={side}114 sideOffset={sideOffset}115 align={align}116 alignOffset={alignOffset}117 className={cn(118 "isolate z-50 h-(--positioner-height) w-(--positioner-width) max-w-(--available-width) transition-[top,left,right,bottom] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] data-instant:transition-none data-[side=bottom]:before:-top-2.5 data-[side=bottom]:before:right-0 data-[side=bottom]:before:left-0",119 className,120 )}121 {...props}122 >123 <NavigationMenuPrimitive.Popup className="data-[ending-style]:easing-[ease] xs:w-(--popup-width) relative h-(--popup-height) w-(--popup-width) origin-(--transform-origin) pixel-border pixel-size-lg bg-popover text-popover-foreground shadow ring-1 ring-foreground/10 transition-[opacity,transform,width,height,scale,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] outline-none data-ending-style:scale-90 data-ending-style:opacity-0 data-ending-style:duration-150 data-starting-style:scale-90 data-starting-style:opacity-0">124 <NavigationMenuPrimitive.Viewport className="relative size-full overflow-hidden" />125 </NavigationMenuPrimitive.Popup>126 </NavigationMenuPrimitive.Positioner>127 </NavigationMenuPrimitive.Portal>128 );129}130
131function NavigationMenuLink({132 className,133 ...props134}: NavigationMenuPrimitive.Link.Props) {135 return (136 <NavigationMenuPrimitive.Link137 data-slot="navigation-menu-link"138 className={cn(139 "flex items-center gap-2 pixel-rounded pixel-size-md p-2 text-sm transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 in-data-[slot=navigation-menu-content]:rounded-md data-active:bg-muted/50 data-active:hover:bg-muted data-active:focus:bg-muted [&_svg:not([class*='size-'])]:size-4",140 className,141 )}142 {...props}143 />144 );145}146
147function NavigationMenuIndicator({148 className,149 ...props150}: React.ComponentPropsWithRef<typeof NavigationMenuPrimitive.Icon>) {151 return (152 <NavigationMenuPrimitive.Icon153 data-slot="navigation-menu-indicator"154 className={cn(155 "top-full z-1 flex h-1.5 items-end justify-center overflow-hidden data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:animate-in data-[state=visible]:fade-in",156 className,157 )}158 {...props}159 >160 <div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />161 </NavigationMenuPrimitive.Icon>162 );163}164
165export {166 NavigationMenu,167 NavigationMenuContent,168 NavigationMenuIndicator,169 NavigationMenuItem,170 NavigationMenuLink,171 NavigationMenuList,172 NavigationMenuPositioner,173 NavigationMenuTrigger,174 navigationMenuTriggerStyle,175};Update the import paths to match your project setup.
import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger,} from "@/components/ui/pxl/navigation-menu"<NavigationMenu> <NavigationMenuList> <NavigationMenuItem> <NavigationMenuTrigger>Item One</NavigationMenuTrigger> <NavigationMenuContent> <NavigationMenuLink>Link</NavigationMenuLink> </NavigationMenuContent> </NavigationMenuItem> </NavigationMenuList></NavigationMenu>Composition
Section titled “Composition”Use the following composition to build a NavigationMenu:
NavigationMenu├── NavigationMenuList│ ├── NavigationMenuItem│ │ ├── NavigationMenuTrigger│ │ └── NavigationMenuContent│ │ ├── NavigationMenuLink│ │ └── NavigationMenuLink│ └── NavigationMenuItem│ └── NavigationMenuLink└── NavigationMenuIndicatorLink Component
Section titled “Link Component”Use the render prop to compose a custom link component such as Next.js Link.
1import Link from "next/link"2
3import {4 NavigationMenuItem,5 NavigationMenuLink,6 navigationMenuTriggerStyle,7} from "@/components/ui/pxl/navigation-menu"8
9export function NavigationMenuDemo() {10 return (11 <NavigationMenuItem>12 <NavigationMenuLink13 render={<Link href="/docs" />}14 className={navigationMenuTriggerStyle()}15 >16 Documentation17 </NavigationMenuLink>18 </NavigationMenuItem>19 )20}API Reference
Section titled “API Reference”See the Base UI Navigation Menu documentation for more information.