{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "navigation-menu",
  "title": "Navigation Menu",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "A site navigation bar with flyout panels sharing one animated viewport that resizes to its content, with keyboard and pointer intent handling, built on Radix.",
  "dependencies": [
    "radix-ui",
    "lucide-react",
    "class-variance-authority"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.ballmac.com/r/direction.json"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/navigation-menu.tsx",
      "content": "// Ballmac UI: Navigation Menu. https://ui.ballmac.com/components/navigation-menu\n// Based on shadcn/ui Navigation Menu (MIT, Copyright (c) 2023 shadcn), restyled with a shared animated viewport that sizes to its content, and exported trigger styles for plain links.\n\"use client\";\n\nimport * as React from \"react\";\nimport { cva } from \"class-variance-authority\";\nimport { ChevronDown } from \"lucide-react\";\nimport { NavigationMenu as Primitive } from \"radix-ui\";\nimport { useDirection } from \"@/lib/ballmac/direction\";\nimport { cn } from \"@/lib/utils\";\n\ntype NavigationMenuProps = React.ComponentProps<typeof Primitive.Root> & {\n  /** Render panels in a shared viewport that resizes between items. Turn off to position each panel under its trigger. */\n  viewport?: boolean;\n  /** Where the shared viewport sits under the menu: from its left edge, or centered under the whole menu (good for wide mega menus). */\n  viewportAlign?: \"start\" | \"center\";\n};\nfunction NavigationMenu({\n  className,\n  children,\n  viewport = true,\n  viewportAlign = \"start\",\n  ...props\n}: NavigationMenuProps) {\n  const dir = useDirection(props.dir);\n  return (\n    <Primitive.Root\n      dir={dir}\n      data-slot=\"navigation-menu\"\n      data-viewport={viewport}\n      className={cn(\n        \"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n      {viewport && <NavigationMenuViewport align={viewportAlign} />}\n    </Primitive.Root>\n  );\n}\n\ntype NavigationMenuListProps = React.ComponentProps<typeof Primitive.List>;\nfunction NavigationMenuList({ className, ...props }: NavigationMenuListProps) {\n  return (\n    <Primitive.List\n      data-slot=\"navigation-menu-list\"\n      className={cn(\"group flex flex-1 list-none items-center justify-center gap-1\", className)}\n      {...props}\n    />\n  );\n}\n\ntype NavigationMenuItemProps = React.ComponentProps<typeof Primitive.Item>;\nfunction NavigationMenuItem({ className, ...props }: NavigationMenuItemProps) {\n  return (\n    <Primitive.Item\n      data-slot=\"navigation-menu-item\"\n      className={cn(\"relative\", className)}\n      {...props}\n    />\n  );\n}\n\n/** Class names for a top-level trigger or link, so plain links can match triggers. */\nconst navigationMenuTriggerStyle = cva(\n  \"group/trigger inline-flex h-9 w-max items-center justify-center gap-1 rounded-md bg-transparent px-3.5 text-sm font-medium outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-[active=true]:bg-accent/60 data-[state=open]:bg-accent/60 data-[state=open]:text-accent-foreground\",\n);\n\ntype NavigationMenuTriggerProps = React.ComponentProps<typeof Primitive.Trigger>;\nfunction NavigationMenuTrigger({\n  className,\n  children,\n  ...props\n}: NavigationMenuTriggerProps) {\n  return (\n    <Primitive.Trigger\n      data-slot=\"navigation-menu-trigger\"\n      className={cn(navigationMenuTriggerStyle(), className)}\n      {...props}\n    >\n      {children}\n      <ChevronDown\n        aria-hidden=\"true\"\n        className=\"relative top-px size-3.5 transition-transform duration-200 group-data-[state=open]/trigger:rotate-180 motion-reduce:transition-none\"\n      />\n    </Primitive.Trigger>\n  );\n}\n\ntype NavigationMenuContentProps = React.ComponentProps<typeof Primitive.Content>;\nfunction NavigationMenuContent({ className, ...props }: NavigationMenuContentProps) {\n  return (\n    <Primitive.Content\n      data-slot=\"navigation-menu-content\"\n      className={cn(\n        \"top-0 start-0 w-full p-2 pe-2.5 data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-32 data-[motion=from-start]:slide-in-from-left-32 data-[motion=to-end]:slide-out-to-right-32 data-[motion=to-start]:slide-out-to-left-32 motion-reduce:animate-none md:absolute md:w-auto\",\n        \"group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-xl group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow-lg\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\ntype NavigationMenuViewportProps = React.ComponentProps<typeof Primitive.Viewport> & {\n  /** Align the viewport to the menu's left edge or center it under the menu. */\n  align?: \"start\" | \"center\";\n};\nfunction NavigationMenuViewport({ className, align = \"start\", ...props }: NavigationMenuViewportProps) {\n  return (\n    <div className={cn(\"absolute top-full start-0 isolate z-50 flex justify-center\", align === \"center\" && \"w-full\")}>\n      <Primitive.Viewport\n        data-slot=\"navigation-menu-viewport\"\n        className={cn(\n          \"origin-top-center relative mt-1.5 shrink-0 h-(--radix-navigation-menu-viewport-height) w-full overflow-hidden rounded-xl border bg-popover text-popover-foreground shadow-[0_12px_36px_-10px_rgb(0_0_0/0.25)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-(--radix-navigation-menu-viewport-width) motion-reduce:animate-none\",\n          className,\n        )}\n        {...props}\n      />\n    </div>\n  );\n}\n\ntype NavigationMenuLinkProps = React.ComponentProps<typeof Primitive.Link> & {\n  /** Style the link like a top-level trigger (for links placed directly in the bar, such as Pricing). Server components can use this instead of calling `navigationMenuTriggerStyle`. */\n  topLevel?: boolean;\n};\nfunction NavigationMenuLink({ className, topLevel = false, ...props }: NavigationMenuLinkProps) {\n  return (\n    <Primitive.Link\n      data-slot=\"navigation-menu-link\"\n      className={cn(\n        topLevel ? navigationMenuTriggerStyle() : \"flex flex-col gap-1 rounded-lg p-2.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 data-[active=true]:bg-accent/60 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\ntype NavigationMenuIndicatorProps = React.ComponentProps<typeof Primitive.Indicator>;\nfunction NavigationMenuIndicator({ className, ...props }: NavigationMenuIndicatorProps) {\n  return (\n    <Primitive.Indicator\n      data-slot=\"navigation-menu-indicator\"\n      className={cn(\n        \"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 motion-reduce:animate-none\",\n        className,\n      )}\n      {...props}\n    >\n      <div className=\"relative top-[60%] size-2 rotate-45 rounded-ss-sm border-t border-s bg-popover shadow-md\" />\n    </Primitive.Indicator>\n  );\n}\n\nexport {\n  NavigationMenu,\n  NavigationMenuList,\n  NavigationMenuItem,\n  NavigationMenuContent,\n  NavigationMenuTrigger,\n  NavigationMenuLink,\n  NavigationMenuIndicator,\n  NavigationMenuViewport,\n  navigationMenuTriggerStyle,\n  type NavigationMenuProps,\n  type NavigationMenuListProps,\n  type NavigationMenuItemProps,\n  type NavigationMenuContentProps,\n  type NavigationMenuTriggerProps,\n  type NavigationMenuLinkProps,\n  type NavigationMenuIndicatorProps,\n  type NavigationMenuViewportProps,\n};\n",
      "type": "registry:ui",
      "target": "@components/ballmac/navigation-menu.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "navigation",
      "header",
      "mega menu",
      "radix"
    ],
    "version": "1.0.0",
    "updated": "2026-09-30",
    "ai": {
      "summary": "Top-level triggers open content panels of links. Use navigationMenuTriggerStyle for plain top-level links.",
      "whenToUse": [
        "Marketing site headers",
        "Docs navigation with grouped links"
      ],
      "whenNotToUse": [
        "An application command menu; use menubar",
        "A small overflow list; use dropdown-menu"
      ],
      "composesWith": [
        "button",
        "separator"
      ],
      "a11y": [
        {
          "keys": "Enter / Space / ArrowDown",
          "action": "Opens the focused panel"
        },
        {
          "keys": "Tab",
          "action": "Moves into the panel links"
        },
        {
          "keys": "ArrowLeft / ArrowRight",
          "action": "Moves between top-level items"
        },
        {
          "keys": "Escape",
          "action": "Closes the panel"
        }
      ],
      "customization": [
        "viewport: shared or per-item",
        "indicator arrow",
        "content width per panel"
      ]
    },
    "source": {
      "name": "shadcn/ui Navigation Menu",
      "url": "https://github.com/shadcn-ui/ui",
      "license": "MIT",
      "copyright": "Copyright (c) 2023 shadcn",
      "modified": true
    },
    "examples": [
      "navigation-menu-demo",
      "navigation-menu-states"
    ],
    "url": "https://ui.ballmac.com/components/navigation-menu"
  },
  "categories": [
    "navigation"
  ],
  "type": "registry:ui"
}