Skip to content
Dethink Components

ComponentsNavigationMenu

NavigationMenu

Group page links in a menu with optional dropdown panels.

On this page

Install component source from the public registry, or use the local workspace package. Follow the setup guide first. The npm package is not published yet.

View registry files
  • React DOM (react-dom)

    Portals for rendering overlay content outside the normal component tree.

Shared foundation: React, clsx for conditional classes, tailwind-merge for resolving utility-class conflicts. Styles use Tailwind CSS and Dethink CSS variables.

Based on this component’s source and registry composition. Libraries used only in showcase examples are excluded.

Import the component into your page or component file.

Usage
import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuIndicator,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
  NavigationMenuViewport,
} from "@dethink/components";

NavigationMenu keeps links as links. Triggers are disclosure buttons with aria-expanded, and panels stay in the navigation's tab order.

Current, disabled, and external states on a persistent top navigation.

Examples that combine components for common tasks.

Brand navbar

A full marketing navbar: brand logo, icon-led menu with rich flyouts and the animated indicator, plus a theme toggle, login, and call-to-action cluster. When the bar gets narrow, the burger expands an integrated panel with accordion submenus — no overlay.

Dethink
Show sourceexamples/navigation-menu/brand-navbar.tsx
examples/navigation-menu/brand-navbar.tsx
"use client";

import { useState } from "react";
import {
  Button,
  IconButton,
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuDescription,
  NavigationMenuFeaturedItem,
  NavigationMenuIndicator,
  NavigationMenuItem,
  NavigationMenuLabel,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuSection,
  NavigationMenuSeparator,
  NavigationMenuTrigger,
} from "@dethink/components";
import {
  BarChart3,
  BookOpen,
  Bot,
  CreditCard,
  LifeBuoy,
  Menu,
  Moon,
  Newspaper,
  Rocket,
  Sparkles,
  Sun,
  Workflow,
  X,
} from "lucide-react";

const productLinks = [
  {
    href: "#analytics",
    label: "Analytics",
    description: "Usage dashboards for every workspace.",
    icon: BarChart3,
  },
  {
    href: "#automation",
    label: "Automation",
    description: "Build workflows that react to events.",
    icon: Workflow,
  },
  {
    href: "#assistant",
    label: "AI Assistant",
    description: "Ask questions across all your data.",
    icon: Bot,
  },
];

const resourceLinks = [
  {
    href: "#docs",
    label: "Documentation",
    description: "Guides, API reference, and recipes.",
    icon: BookOpen,
  },
  {
    href: "#blog",
    label: "Blog",
    description: "Product updates and engineering notes.",
    icon: Newspaper,
  },
  {
    href: "#support",
    label: "Support",
    description: "Talk to a human when you need one.",
    icon: LifeBuoy,
  },
];

function BrandLogo() {
  return (
    <a
      href="#home"
      className="focus-visible:ring-ring focus-visible:ring-offset-background flex shrink-0 items-center gap-2 rounded-md focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
    >
      <span
        aria-hidden="true"
        className="from-primary to-primary/60 text-primary-foreground flex size-8 items-center justify-center rounded-lg bg-gradient-to-br shadow-sm"
      >
        <Sparkles className="size-4" />
      </span>
      <span className="text-foreground text-base font-semibold tracking-tight">
        Dethink
      </span>
    </a>
  );
}

/**
 * The same destinations power both layouts. In the stacked (mobile) layout the
 * flyout panels are restyled into in-place accordions: the item stacks, the
 * trigger spans the row, and the content swaps its absolute side panel for a
 * static full-width block.
 */
function BrandNavItems({ stacked = false }: { stacked?: boolean }) {
  const itemClass = stacked ? "w-full flex-col items-stretch" : undefined;
  const triggerClass = stacked
    ? "w-full [&>[data-slot=navigation-menu-trigger-icon]]:ms-auto"
    : undefined;
  const contentClass = stacked
    ? "static w-full max-w-none flex-col border-0 bg-transparent p-0 ps-[var(--dt-space-2)] pt-[var(--dt-space-1)] shadow-none"
    : undefined;
  const linkClass = stacked ? "w-full" : undefined;

  return (
    <>
      <NavigationMenuItem className={itemClass} value="product">
        <NavigationMenuTrigger className={triggerClass}>
          <Rocket aria-hidden="true" className="text-muted-foreground size-4" />
          Product
        </NavigationMenuTrigger>
        <NavigationMenuContent className={contentClass}>
          <NavigationMenuFeaturedItem
            href="#platform"
            className={stacked ? "w-full" : undefined}
          >
            Platform overview
            <NavigationMenuDescription>
              Analytics, automation, and AI in one workspace.
            </NavigationMenuDescription>
          </NavigationMenuFeaturedItem>
          {stacked ? null : <NavigationMenuSeparator orientation="vertical" />}
          <NavigationMenuSection className={stacked ? "w-full" : undefined}>
            <NavigationMenuLabel>Products</NavigationMenuLabel>
            {productLinks.map(({ href, label, description, icon: Icon }) => (
              <NavigationMenuLink
                key={href}
                href={href}
                icon={<Icon aria-hidden="true" />}
              >
                {label}
                <NavigationMenuDescription>
                  {description}
                </NavigationMenuDescription>
              </NavigationMenuLink>
            ))}
          </NavigationMenuSection>
        </NavigationMenuContent>
      </NavigationMenuItem>

      <NavigationMenuItem className={itemClass} value="resources">
        <NavigationMenuTrigger className={triggerClass}>
          <BookOpen
            aria-hidden="true"
            className="text-muted-foreground size-4"
          />
          Resources
        </NavigationMenuTrigger>
        <NavigationMenuContent className={contentClass}>
          <NavigationMenuSection className={stacked ? "w-full" : undefined}>
            <NavigationMenuLabel>Learn</NavigationMenuLabel>
            {resourceLinks.map(({ href, label, description, icon: Icon }) => (
              <NavigationMenuLink
                key={href}
                href={href}
                icon={<Icon aria-hidden="true" />}
              >
                {label}
                <NavigationMenuDescription>
                  {description}
                </NavigationMenuDescription>
              </NavigationMenuLink>
            ))}
          </NavigationMenuSection>
        </NavigationMenuContent>
      </NavigationMenuItem>

      <NavigationMenuItem className={stacked ? "w-full" : undefined}>
        <NavigationMenuLink
          current
          href="#pricing"
          icon={<CreditCard aria-hidden="true" />}
          className={linkClass}
        >
          Pricing
        </NavigationMenuLink>
      </NavigationMenuItem>
    </>
  );
}

export function NavigationMenuBrandNavbar() {
  // Local to the example — a real app would drive this from its theme provider.
  const [darkPreview, setDarkPreview] = useState(false);
  const [mobileOpen, setMobileOpen] = useState(false);
  const ThemeIcon = darkPreview ? Moon : Sun;

  return (
    // The container query keeps the collapse tied to the navbar's own width,
    // so the example adapts to whatever column hosts it.
    <div className="@container min-h-[26rem]">
      <header className="border-border bg-background/80 supports-[backdrop-filter]:bg-background/60 rounded-xl border shadow-sm backdrop-blur">
        <div className="flex h-14 items-center gap-2 px-3">
          <BrandLogo />

          {/* Wide: icon-led navigation with the animated indicator. The panel
              max-width is capped so flyouts stay inside the navbar column. */}
          <NavigationMenu
            aria-label="Main"
            className="[--dt-navigation-menu-content-max-width:34rem] @max-3xl:hidden"
          >
            <NavigationMenuList>
              <BrandNavItems />
              <NavigationMenuIndicator />
            </NavigationMenuList>
          </NavigationMenu>

          <div className="ml-auto flex items-center gap-1.5">
            <IconButton
              aria-label={
                darkPreview ? "Switch to light theme" : "Switch to dark theme"
              }
              aria-pressed={darkPreview}
              variant="ghost"
              size="sm"
              onClick={() => setDarkPreview((previous) => !previous)}
            >
              <ThemeIcon aria-hidden="true" />
            </IconButton>

            <span
              aria-hidden="true"
              className="bg-border mx-1 h-5 w-px @max-md:hidden"
            />

            <Button variant="ghost" size="sm" className="@max-md:hidden">
              Log in
            </Button>
            <Button size="sm">Get started</Button>

            {/* Narrow: the burger expands an integrated panel below the bar —
                no overlay, the navbar simply grows. */}
            <IconButton
              aria-label={mobileOpen ? "Close navigation" : "Open navigation"}
              aria-expanded={mobileOpen}
              aria-controls="brand-navbar-mobile-panel"
              variant="ghost"
              size="sm"
              className="@3xl:hidden"
              onClick={() => setMobileOpen((previous) => !previous)}
            >
              {mobileOpen ? (
                <X aria-hidden="true" />
              ) : (
                <Menu aria-hidden="true" />
              )}
            </IconButton>
          </div>
        </div>

        <div
          id="brand-navbar-mobile-panel"
          hidden={!mobileOpen}
          className="border-border border-t @3xl:hidden"
        >
          <div className="space-y-3 px-3 py-3">
            <NavigationMenu
              aria-label="Main"
              orientation="vertical"
              variant="quiet"
              className="w-full"
            >
              <NavigationMenuList className="w-full">
                <BrandNavItems stacked />
              </NavigationMenuList>
            </NavigationMenu>
            {/* Mirror the login action while the bar hides it. */}
            <div className="border-border border-t pt-3 @md:hidden">
              <Button variant="outline" size="sm" className="w-full">
                Log in
              </Button>
            </div>
          </div>
        </div>
      </header>
    </div>
  );
}

Product navigation

Rich flyout panels with a featured card, grouped links, icons, descriptions, and the animated indicator.

Show sourceexamples/navigation-menu/product-nav.tsx
examples/navigation-menu/product-nav.tsx
"use client";

import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuDescription,
  NavigationMenuFeaturedItem,
  NavigationMenuIndicator,
  NavigationMenuItem,
  NavigationMenuLabel,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuSection,
  NavigationMenuSeparator,
  NavigationMenuTrigger,
} from "@dethink/components";
import { BarChart3, Workflow } from "lucide-react";

export function NavigationMenuProductNav() {
  return (
    <div className="min-h-[22rem]">
      <NavigationMenu aria-label="Product">
        <NavigationMenuList>
          <NavigationMenuItem value="platform">
            <NavigationMenuTrigger>Platform</NavigationMenuTrigger>
            <NavigationMenuContent>
              <NavigationMenuFeaturedItem href="#platform">
                Platform overview
                <NavigationMenuDescription>
                  Analytics, automation, and reporting in one workspace.
                </NavigationMenuDescription>
              </NavigationMenuFeaturedItem>
              <NavigationMenuSeparator orientation="vertical" />
              <NavigationMenuSection>
                <NavigationMenuLabel>Products</NavigationMenuLabel>
                <NavigationMenuLink
                  href="#analytics"
                  icon={<BarChart3 aria-hidden="true" />}
                >
                  Analytics
                  <NavigationMenuDescription>
                    Usage dashboards for every workspace.
                  </NavigationMenuDescription>
                </NavigationMenuLink>
                <NavigationMenuLink
                  href="#automation"
                  icon={<Workflow aria-hidden="true" />}
                >
                  Automation
                  <NavigationMenuDescription>
                    Build workflows that react to events.
                  </NavigationMenuDescription>
                </NavigationMenuLink>
              </NavigationMenuSection>
            </NavigationMenuContent>
          </NavigationMenuItem>
          <NavigationMenuItem value="solutions">
            <NavigationMenuTrigger>Solutions</NavigationMenuTrigger>
            <NavigationMenuContent>
              <NavigationMenuSection>
                <NavigationMenuLabel>By team</NavigationMenuLabel>
                <NavigationMenuLink href="#product-teams">
                  Product teams
                </NavigationMenuLink>
                <NavigationMenuLink href="#data-teams">
                  Data teams
                </NavigationMenuLink>
              </NavigationMenuSection>
            </NavigationMenuContent>
          </NavigationMenuItem>
          <NavigationMenuItem>
            <NavigationMenuLink current href="#pricing">
              Pricing
            </NavigationMenuLink>
          </NavigationMenuItem>
          <NavigationMenuIndicator />
        </NavigationMenuList>
      </NavigationMenu>
    </div>
  );
}

App topbar with mobile handoff

A compact quiet nav on desktop; on small screens the same links hand off to a Dialog. Resize the viewport to see the collapse.

Acme Cloud
workspace: prod
Show sourceexamples/navigation-menu/app-topbar.tsx
examples/navigation-menu/app-topbar.tsx
"use client";

import {
  Dialog,
  DialogContent,
  DialogTitle,
  DialogTrigger,
  NavigationMenu,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
} from "@dethink/components";
import { Menu } from "lucide-react";

const sections = [
  { href: "#dashboard", label: "Dashboard", current: true },
  { href: "#deployments", label: "Deployments", current: false },
  { href: "#monitoring", label: "Monitoring", current: false },
  { href: "#team", label: "Team", current: false },
];

export function NavigationMenuAppTopbar() {
  return (
    <header className="border-border bg-muted/30 flex items-center justify-between gap-4 rounded-md border px-4 py-2">
      <span className="text-foreground text-sm font-semibold">Acme Cloud</span>

      {/* Desktop: persistent quiet nav. */}
      <NavigationMenu
        aria-label="Dashboard"
        variant="quiet"
        size="sm"
        className="max-md:hidden"
      >
        <NavigationMenuList>
          {sections.map((section) => (
            <NavigationMenuItem key={section.href}>
              <NavigationMenuLink current={section.current} href={section.href}>
                {section.label}
              </NavigationMenuLink>
            </NavigationMenuItem>
          ))}
        </NavigationMenuList>
      </NavigationMenu>

      {/* Mobile: the same links hand off to a Dialog. NavigationMenu stays a
          navigation primitive — the Dialog owns the overlay behavior. */}
      <div className="md:hidden">
        <Dialog>
          <DialogTrigger
            aria-label="Open navigation"
            size="icon"
            variant="outline"
          >
            <Menu aria-hidden="true" className="size-4" />
          </DialogTrigger>
          <DialogContent>
            <DialogTitle>Navigate</DialogTitle>
            <div className="px-[var(--dt-space-6)] pb-[var(--dt-space-6)]">
              <NavigationMenu
                aria-label="Dashboard"
                orientation="vertical"
                variant="quiet"
              >
                <NavigationMenuList>
                  {sections.map((section) => (
                    <NavigationMenuItem key={section.href}>
                      <NavigationMenuLink
                        current={section.current}
                        href={section.href}
                      >
                        {section.label}
                      </NavigationMenuLink>
                    </NavigationMenuItem>
                  ))}
                </NavigationMenuList>
              </NavigationMenu>
            </div>
          </DialogContent>
        </Dialog>
      </div>

      <span className="text-muted-foreground text-sm max-md:hidden">
        workspace: prod
      </span>
    </header>
  );
}

Mobile navigation drawer

A phone-sized in-page drawer: a disclosure button toggles the panel, and the vertical menu restyles its flyout into an accordion — links, icons, current state, and auth actions stay intact.

Show sourceexamples/navigation-menu/mobile-drawer.tsx
examples/navigation-menu/mobile-drawer.tsx
"use client";

import { useState } from "react";
import {
  Button,
  IconButton,
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuDescription,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuSection,
  NavigationMenuTrigger,
} from "@dethink/components";
import {
  BarChart3,
  Bot,
  CreditCard,
  Home,
  LifeBuoy,
  Menu,
  Sparkles,
  Workflow,
  X,
} from "lucide-react";

/**
 * A self-contained mobile navigation drawer: a disclosure button toggles an
 * in-page panel (no overlay, so no Dialog needed), and the vertical
 * NavigationMenu turns its flyout into an accordion by restyling
 * NavigationMenuContent to flow in place.
 */
export function NavigationMenuMobileDrawer() {
  const [open, setOpen] = useState(true);

  return (
    <div className="border-border bg-background mx-auto w-full max-w-[22rem] overflow-hidden rounded-2xl border shadow-sm">
      <div className="flex h-14 items-center justify-between px-4">
        <a
          href="#home"
          className="focus-visible:ring-ring focus-visible:ring-offset-background flex items-center gap-2 rounded-md focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
        >
          <span
            aria-hidden="true"
            className="from-primary to-primary/60 text-primary-foreground flex size-7 items-center justify-center rounded-lg bg-gradient-to-br"
          >
            <Sparkles className="size-3.5" />
          </span>
          <span className="text-foreground text-sm font-semibold tracking-tight">
            Dethink
          </span>
        </a>
        <IconButton
          aria-label={open ? "Close navigation" : "Open navigation"}
          aria-expanded={open}
          aria-controls="mobile-drawer-panel"
          variant="ghost"
          size="sm"
          onClick={() => setOpen((previous) => !previous)}
        >
          {open ? <X aria-hidden="true" /> : <Menu aria-hidden="true" />}
        </IconButton>
      </div>

      <div
        id="mobile-drawer-panel"
        hidden={!open}
        className="border-border border-t"
      >
        <div className="space-y-4 px-3 py-4">
          <NavigationMenu
            aria-label="Main"
            orientation="vertical"
            variant="quiet"
            className="w-full"
          >
            <NavigationMenuList className="w-full">
              <NavigationMenuItem className="w-full">
                <NavigationMenuLink
                  current
                  href="#home"
                  icon={<Home aria-hidden="true" />}
                  className="w-full"
                >
                  Home
                </NavigationMenuLink>
              </NavigationMenuItem>

              {/* The flyout becomes an accordion: className swaps the
                  absolute side-panel for a static, full-width block. */}
              <NavigationMenuItem
                className="w-full flex-col items-stretch"
                value="products"
              >
                <NavigationMenuTrigger className="w-full justify-between">
                  Products
                </NavigationMenuTrigger>
                <NavigationMenuContent className="static w-full max-w-none border-0 bg-transparent p-0 ps-[var(--dt-space-2)] shadow-none">
                  <NavigationMenuSection className="w-full">
                    <NavigationMenuLink
                      href="#analytics"
                      icon={<BarChart3 aria-hidden="true" />}
                    >
                      Analytics
                      <NavigationMenuDescription>
                        Usage dashboards for every workspace.
                      </NavigationMenuDescription>
                    </NavigationMenuLink>
                    <NavigationMenuLink
                      href="#automation"
                      icon={<Workflow aria-hidden="true" />}
                    >
                      Automation
                      <NavigationMenuDescription>
                        Build workflows that react to events.
                      </NavigationMenuDescription>
                    </NavigationMenuLink>
                    <NavigationMenuLink
                      href="#assistant"
                      icon={<Bot aria-hidden="true" />}
                    >
                      AI Assistant
                      <NavigationMenuDescription>
                        Ask questions across all your data.
                      </NavigationMenuDescription>
                    </NavigationMenuLink>
                  </NavigationMenuSection>
                </NavigationMenuContent>
              </NavigationMenuItem>

              <NavigationMenuItem className="w-full">
                <NavigationMenuLink
                  href="#pricing"
                  icon={<CreditCard aria-hidden="true" />}
                  className="w-full"
                >
                  Pricing
                </NavigationMenuLink>
              </NavigationMenuItem>
              <NavigationMenuItem className="w-full">
                <NavigationMenuLink
                  external
                  href="https://status.example.com"
                  icon={<LifeBuoy aria-hidden="true" />}
                  className="w-full"
                >
                  Status
                </NavigationMenuLink>
              </NavigationMenuItem>
            </NavigationMenuList>
          </NavigationMenu>

          <div className="border-border space-y-2 border-t pt-4">
            <Button variant="outline" size="sm" className="w-full">
              Log in
            </Button>
            <Button size="sm" className="w-full">
              Get started
            </Button>
          </div>
        </div>
      </div>
    </div>
  );
}

Documentation hub

Underline variant with grouped guide flyouts and aria-current=location for the active page.

Show sourceexamples/navigation-menu/docs-hub.tsx
examples/navigation-menu/docs-hub.tsx
"use client";

import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuDescription,
  NavigationMenuItem,
  NavigationMenuLabel,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuSection,
  NavigationMenuSeparator,
  NavigationMenuTrigger,
} from "@dethink/components";

export function NavigationMenuDocsHub() {
  return (
    <div className="min-h-[20rem]">
      <NavigationMenu aria-label="Documentation" variant="underline">
        <NavigationMenuList>
          <NavigationMenuItem value="guides">
            <NavigationMenuTrigger>Guides</NavigationMenuTrigger>
            <NavigationMenuContent>
              <NavigationMenuSection>
                <NavigationMenuLabel>Getting started</NavigationMenuLabel>
                <NavigationMenuLink current="location" href="#install">
                  Installation
                  <NavigationMenuDescription>
                    Registry setup and base tokens.
                  </NavigationMenuDescription>
                </NavigationMenuLink>
                <NavigationMenuLink href="#theming">
                  Theming
                  <NavigationMenuDescription>
                    Light, dark, density, and brand palettes.
                  </NavigationMenuDescription>
                </NavigationMenuLink>
              </NavigationMenuSection>
              <NavigationMenuSeparator orientation="vertical" />
              <NavigationMenuSection>
                <NavigationMenuLabel>Recipes</NavigationMenuLabel>
                <NavigationMenuLink href="#forms">Forms</NavigationMenuLink>
                <NavigationMenuLink href="#tables">Tables</NavigationMenuLink>
                <NavigationMenuLink href="#navigation">
                  Navigation
                </NavigationMenuLink>
              </NavigationMenuSection>
            </NavigationMenuContent>
          </NavigationMenuItem>
          <NavigationMenuItem value="reference">
            <NavigationMenuTrigger>Reference</NavigationMenuTrigger>
            <NavigationMenuContent>
              <NavigationMenuSection>
                <NavigationMenuLink href="#api">
                  Component API
                </NavigationMenuLink>
                <NavigationMenuLink href="#tokens">Tokens</NavigationMenuLink>
              </NavigationMenuSection>
            </NavigationMenuContent>
          </NavigationMenuItem>
          <NavigationMenuItem>
            <NavigationMenuLink href="#changelog">Changelog</NavigationMenuLink>
          </NavigationMenuItem>
        </NavigationMenuList>
      </NavigationMenu>
    </div>
  );
}

Dashboard composition

A quiet topbar plus a vertical section nav composing an app shell — without absorbing Sidebar's job.

Insights

Revenue report

Updated from pipeline run #428.

Two NavigationMenu instances compose the shell: a quiet topbar for workspace areas and a vertical section list for the active report. A full application shell with a collapsible sidebar stays out of scope for NavigationMenu — that is the future Sidebar component.

Show sourceexamples/navigation-menu/dashboard.tsx
examples/navigation-menu/dashboard.tsx
"use client";

import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
  NavigationMenu,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
} from "@dethink/components";

export function NavigationMenuDashboard() {
  return (
    <div className="space-y-4">
      <header className="border-border bg-muted/30 flex items-center justify-between gap-4 rounded-md border px-4 py-2">
        <span className="text-foreground text-sm font-semibold">Insights</span>
        <NavigationMenu aria-label="Workspace areas" size="sm" variant="quiet">
          <NavigationMenuList>
            <NavigationMenuItem>
              <NavigationMenuLink href="#home">Home</NavigationMenuLink>
            </NavigationMenuItem>
            <NavigationMenuItem>
              <NavigationMenuLink current href="#reports">
                Reports
              </NavigationMenuLink>
            </NavigationMenuItem>
            <NavigationMenuItem>
              <NavigationMenuLink href="#alerts">Alerts</NavigationMenuLink>
            </NavigationMenuItem>
          </NavigationMenuList>
        </NavigationMenu>
      </header>

      <div className="grid gap-4 md:grid-cols-[12rem_minmax(0,1fr)]">
        <NavigationMenu
          aria-label="Report sections"
          orientation="vertical"
          size="sm"
          variant="quiet"
        >
          <NavigationMenuList>
            <NavigationMenuItem>
              <NavigationMenuLink current="location" href="#revenue">
                Revenue
              </NavigationMenuLink>
            </NavigationMenuItem>
            <NavigationMenuItem>
              <NavigationMenuLink href="#retention">
                Retention
              </NavigationMenuLink>
            </NavigationMenuItem>
            <NavigationMenuItem>
              <NavigationMenuLink href="#usage">Usage</NavigationMenuLink>
            </NavigationMenuItem>
          </NavigationMenuList>
        </NavigationMenu>

        <Card>
          <CardHeader>
            <CardTitle>Revenue report</CardTitle>
            <CardDescription>Updated from pipeline run #428.</CardDescription>
          </CardHeader>
          <CardContent>
            <p className="text-muted-foreground text-sm">
              Two NavigationMenu instances compose the shell: a quiet topbar for
              workspace areas and a vertical section list for the active report.
              A full application shell with a collapsible sidebar stays out of
              scope for NavigationMenu — that is the future Sidebar component.
            </p>
          </CardContent>
        </Card>
      </div>
    </div>
  );
}

Overflow collapse

Secondary destinations collapse behind a More disclosure on narrow screens and render inline when space allows.

Show sourceexamples/navigation-menu/overflow.tsx
examples/navigation-menu/overflow.tsx
"use client";

import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuSection,
  NavigationMenuTrigger,
} from "@dethink/components";

export function NavigationMenuOverflow() {
  return (
    <div className="min-h-[16rem]">
      <NavigationMenu aria-label="Product">
        <NavigationMenuList>
          <NavigationMenuItem>
            <NavigationMenuLink current href="#overview">
              Overview
            </NavigationMenuLink>
          </NavigationMenuItem>
          <NavigationMenuItem>
            <NavigationMenuLink href="#projects">Projects</NavigationMenuLink>
          </NavigationMenuItem>
          {/* Secondary destinations stay reachable on narrow screens by
              collapsing behind a disclosure trigger instead of wrapping. */}
          <NavigationMenuItem className="lg:hidden" value="more">
            <NavigationMenuTrigger>More</NavigationMenuTrigger>
            <NavigationMenuContent>
              <NavigationMenuSection>
                <NavigationMenuLink href="#reports">Reports</NavigationMenuLink>
                <NavigationMenuLink href="#audit">Audit log</NavigationMenuLink>
                <NavigationMenuLink href="#settings">
                  Settings
                </NavigationMenuLink>
              </NavigationMenuSection>
            </NavigationMenuContent>
          </NavigationMenuItem>
          {/* On wide screens the same links render inline. */}
          <NavigationMenuItem className="max-lg:hidden">
            <NavigationMenuLink href="#reports">Reports</NavigationMenuLink>
          </NavigationMenuItem>
          <NavigationMenuItem className="max-lg:hidden">
            <NavigationMenuLink href="#audit">Audit log</NavigationMenuLink>
          </NavigationMenuItem>
          <NavigationMenuItem className="max-lg:hidden">
            <NavigationMenuLink href="#settings">Settings</NavigationMenuLink>
          </NavigationMenuItem>
        </NavigationMenuList>
      </NavigationMenu>
    </div>
  );
}
NavigationMenu anatomy
PropWhat it doesDefault
variant / size / orientation"default" | "quiet" | "underline" / "sm" | "md" | "lg" / "horizontal" | "vertical"Token-backed presentation of the whole menu; links and triggers inherit these through context."default" / "md" / "horizontal"
value / defaultValue / onValueChangestring | null / string | null / (value) => voidControlled or uncontrolled open flyout item, keyed by NavigationMenuItem value.Not set
activationMode"click" | "hover" | "focus" | "manual"How triggers open panels. Hover adds an intent delay and keeps click/keyboard activation working; manual leaves all state changes to the consumer."click"
delay / closeDelaynumber / numberHover-intent timings in milliseconds for hover activation.150 / 300
motion"none" | "subtle" | "standard" | "expressive"CSS motion preset for panel transitions, directional slides, and staggered reveal. All movement respects prefers-reduced-motion."standard"
NavigationMenuLink — currentboolean | "page" | "location"Marks the current destination with aria-current and a stable data-current attribute.Not set
NavigationMenuLink — disabled / external / icon / asChildboolean / boolean / ReactNode / booleanDisabled links drop their href and expose aria-disabled; external links get safe rel handling; asChild composes router links.Not set
NavigationMenuItem — valuestringStable identity for controlled state, indicator mapping, and directional transitions.auto
NavigationMenuTriggerbutton (disclosure semantics)Native button exposing aria-expanded/aria-controls; never role=menu. showChevron hides the built-in caret.Not set
NavigationMenuViewport / NavigationMenuIndicatoroptional anatomyShared morphing panel host and animated active-item marker; both are optional layers over the inline flyout behavior.Not set