PRIZM 4.0DSTA
All components

Navigation Menu

Multi-level navigation bar.

stableBase UI Navigation Menu

Preview

Code

tsx
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

PropTypeDefaultDescription
classNamestringAdditional Tailwind classes, merged with the component's defaults via cn().

Sub-components

NavigationMenu.ListTop-level horizontal nav list.
NavigationMenu.ItemEach top-level item.
NavigationMenu.TriggerItem that opens a sub-menu.
NavigationMenu.ContentSub-menu popup content.
NavigationMenu.LinkDirect 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.

tsx
"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.

java
import design.prizm.fx.controls.PrizmNavigationMenu;

PrizmNavigationMenu()
PropTypeDefaultDescription
addMenu(String label, MenuItem... items) → MenuButtonAdd 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.