Navigation Menu
Multi-level navigation bar.
Preview
Code
import {
NavigationMenu, NavigationMenuContent, NavigationMenuItem,
NavigationMenuList, NavigationMenuTrigger,
} from "@/components/ui/navigation-menu";
export function Example() {
return (
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Products</NavigationMenuTrigger>
<NavigationMenuContent className="p-3 w-48">
<ul className="space-y-1 text-sm">
<li><Link href="/c3" className="block rounded px-2 py-1 hover:bg-bg-muted">C3 Suite</Link></li>
<li><Link href="/enterprise" className="block rounded px-2 py-1 hover:bg-bg-muted">Enterprise Portal</Link></li>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | — | Additional Tailwind classes, merged with the component's defaults via cn(). |
Sub-components
NavigationMenu.List— Top-level horizontal nav list.NavigationMenu.Item— Each top-level item.NavigationMenu.Trigger— Item that opens a sub-menu.NavigationMenu.Content— Sub-menu popup content.NavigationMenu.Link— Direct nav link (no sub-menu).Built on Base UI Navigation Menu. Exports are prefixed `NavigationMenu.*` (namespace pattern).
All components also accept standard HTML attributes for their root element (e.g. `id`, `aria-*`, `data-*`, event handlers) and forward `ref` where applicable.
Source
The full implementation of components/ui/navigation-menu.tsx is below — copy it into your project and own it. Some components import the cn helper from lib/utils or other primitives; copy those too.
"use client";
import { cn } from "@/lib/utils";
import { NavigationMenu as BaseNav } from "@base-ui-components/react/navigation-menu";
import { ChevronDown } from "lucide-react";
import type { ComponentPropsWithoutRef } from "react";
export const NavigationMenu = BaseNav.Root;
export function NavigationMenuList({
className,
...props
}: ComponentPropsWithoutRef<typeof BaseNav.List>) {
return (
<BaseNav.List
className={cn("flex flex-row items-center gap-1 list-none m-0 p-0", className)}
{...props}
/>
);
}
export const NavigationMenuItem = BaseNav.Item;
export const NavigationMenuLink = BaseNav.Link;
export function NavigationMenuTrigger({
className,
children,
...props
}: ComponentPropsWithoutRef<typeof BaseNav.Trigger>) {
return (
<BaseNav.Trigger
className={cn(
"group inline-flex h-9 items-center justify-center gap-1 rounded-md px-3 py-2 text-sm font-medium transition-colors",
"text-fg-muted hover:bg-bg-muted hover:text-fg",
"focus-visible:outline-1 focus-visible:outline-offset-0 focus-visible:outline-accent",
"data-[popup-open]:bg-bg-muted data-[popup-open]:text-fg",
"aria-disabled:pointer-events-none aria-disabled:opacity-50",
className,
)}
{...props}
>
{children}
<ChevronDown
className="h-3.5 w-3.5 opacity-60 transition-transform duration-200 group-data-[popup-open]:rotate-180"
aria-hidden
/>
</BaseNav.Trigger>
);
}
export function NavigationMenuContent({
className,
...props
}: ComponentPropsWithoutRef<typeof BaseNav.Popup>) {
return (
<BaseNav.Portal>
<BaseNav.Positioner sideOffset={8}>
<BaseNav.Popup
className={cn(
"z-50 overflow-hidden rounded-md border border-border bg-surface-elevated shadow-md",
"data-[starting-style]:opacity-0 data-[starting-style]:scale-95",
"data-[ending-style]:opacity-0 data-[ending-style]:scale-95",
"transition-all duration-150",
className,
)}
{...props}
/>
</BaseNav.Positioner>
</BaseNav.Portal>
);
}
export function NavigationMenuIndicator({
className,
...props
}: ComponentPropsWithoutRef<typeof BaseNav.Icon>) {
return (
<BaseNav.Icon className={cn("flex h-1.5 w-1.5 rounded-full bg-accent", className)} {...props} />
);
}
export function NavigationMenuViewport({
className,
...props
}: ComponentPropsWithoutRef<typeof BaseNav.Viewport>) {
return (
<div className="absolute left-0 top-full flex justify-center">
<BaseNav.Viewport className={cn("z-50", className)} {...props} />
</div>
);
}JavaFX
Ships in the PRIZM JavaFX library for thick-client C3 apps as PrizmNavigationMenu (extends HBox). Run the gallery to see it natively.
import design.prizm.fx.controls.PrizmNavigationMenu;
PrizmNavigationMenu()| Prop | Type | Default | Description |
|---|---|---|---|
| addMenu | (String label, MenuItem... items) → MenuButton | — | Add a top-level trigger with its dropdown items; returns the MenuButton. |
An HBox of MenuButton triggers (a MenuBar can't show/animate a trigger chevron). Each trigger has a chevron graphic that rotates down→up (150ms) on open, styled by .prizm-nav-trigger; dropdowns reuse the .context-menu / .menu-item rules. Mirrors components/ui/navigation-menu.tsx.