# Navigation Menu

A horizontal row of site links, where some open a panel of related links.

```tsx
import { BellIcon, GlobeIcon, ServerIcon, ShieldAlertIcon } from "lucide-react"
import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, navigationMenuTriggerStyle } from "@zenoxai/ui/components/navigation-menu"

function NavigationMenuDemo() {
  return (
    <NavigationMenu>
      <NavigationMenuList>
        <NavigationMenuItem>
          <NavigationMenuTrigger>Monitoring</NavigationMenuTrigger>
          <NavigationMenuContent>
            <ul className="grid w-80 gap-1">
              <li>
                <NavigationMenuLink href="#" className="items-start">
                  <BellIcon className="mt-0.5" />
                  <div className="flex flex-col gap-0.5">
                    <span className="font-medium">Alerts</span>
                    <span className="text-text-muted">
                      Detections waiting for triage.
                    </span>
                  </div>
                </NavigationMenuLink>
              </li>
              <li>
                <NavigationMenuLink href="#" className="items-start">
                  <ShieldAlertIcon className="mt-0.5" />
                  <div className="flex flex-col gap-0.5">
                    <span className="font-medium">Vulnerabilities</span>
                    <span className="text-text-muted">
                      CVEs found on your exposed assets.
                    </span>
                  </div>
                </NavigationMenuLink>
              </li>
            </ul>
          </NavigationMenuContent>
        </NavigationMenuItem>
        <NavigationMenuItem>
          <NavigationMenuTrigger>Inventory</NavigationMenuTrigger>
          <NavigationMenuContent>
            <ul className="grid w-80 gap-1">
              <li>
                <NavigationMenuLink href="#" className="items-start">
                  <GlobeIcon className="mt-0.5" />
                  <div className="flex flex-col gap-0.5">
                    <span className="font-medium">Domains</span>
                    <span className="text-text-muted">
                      Registered domains and their DNS records.
                    </span>
                  </div>
                </NavigationMenuLink>
              </li>
              <li>
                <NavigationMenuLink href="#" className="items-start">
                  <ServerIcon className="mt-0.5" />
                  <div className="flex flex-col gap-0.5">
                    <span className="font-medium">Hosts</span>
                    <span className="text-text-muted">
                      IP addresses and the services they expose.
                    </span>
                  </div>
                </NavigationMenuLink>
              </li>
            </ul>
          </NavigationMenuContent>
        </NavigationMenuItem>
        <NavigationMenuItem>
          <NavigationMenuLink href="#" className={navigationMenuTriggerStyle()}>
            Reports
          </NavigationMenuLink>
        </NavigationMenuItem>
      </NavigationMenuList>
    </NavigationMenu>
  )
}
```

## Usage

```tsx
import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
} from "@zenoxai/ui/components/navigation-menu"
```

```tsx
<NavigationMenu>
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuTrigger>Monitoring</NavigationMenuTrigger>
      <NavigationMenuContent>
        <NavigationMenuLink href="/alerts">Alerts</NavigationMenuLink>
      </NavigationMenuContent>
    </NavigationMenuItem>
  </NavigationMenuList>
</NavigationMenu>
```

Use a navigation menu for top-level navigation across a site or a product area: a marketing
site, a portal header, the sections of a large module. Each `NavigationMenuItem` holds either
a trigger with a content panel, or a single link. Give a top-level link the trigger look with
`className={navigationMenuTriggerStyle()}`.

`NavigationMenu` renders the popup that holds the open panel, so there is nothing else to
place. Use `align` on `NavigationMenu` to align the popup to the trigger's `start`, `center` or
`end`. Size the content of each panel (`w-80` above); the popup animates between sizes as the
user moves across triggers.

The navigation menu is for links only. For actions on the current page, use a
[Dropdown Menu](/components/dropdown-menu) or a [Menubar](/components/menubar). For the app
shell, use the [Sidebar](/components/sidebar).

## Examples

### Links only

A row of plain links styled as triggers. Set `active` on the link to the current page: it takes
the selection colors, a tinted fill and text, which hover does not change.

```tsx
import { NavigationMenu, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, navigationMenuTriggerStyle } from "@zenoxai/ui/components/navigation-menu"

function NavigationMenuLinks() {
  return (
    <NavigationMenu>
      <NavigationMenuList>
        <NavigationMenuItem>
          <NavigationMenuLink
            href="#"
            active
            className={navigationMenuTriggerStyle()}
          >
            Overview
          </NavigationMenuLink>
        </NavigationMenuItem>
        <NavigationMenuItem>
          <NavigationMenuLink href="#" className={navigationMenuTriggerStyle()}>
            Threat intelligence
          </NavigationMenuLink>
        </NavigationMenuItem>
        <NavigationMenuItem>
          <NavigationMenuLink href="#" className={navigationMenuTriggerStyle()}>
            Brand protection
          </NavigationMenuLink>
        </NavigationMenuItem>
      </NavigationMenuList>
    </NavigationMenu>
  )
}
```

## Accessibility

- The menu is a `<nav>` with a list of items. Left and Right move between top-level items. A
  trigger is a button with `aria-expanded`; it opens on hover and on click, and Enter, Space
  or Arrow Down open it from the keyboard.
- Tab moves through the links of an open panel, and Escape closes it and returns focus to its
  trigger.
- `active` on a link sets `aria-current="page"`. Set it on exactly one link.

## API reference

`import { ... } from "@zenoxai/ui/components/navigation-menu"`

### NavigationMenu

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| actionsRef | `RefObject<NavigationMenuRootActions \| null>` |  | A ref to imperative actions. - `unmount`: Ends the closing phase of the navigation menu popup after an externally controlled closing animation finishes. Call `preventUnmountOnClose()` in `onValueChange` first, otherwise the navigation menu popup completes closing on its own. Whether it leaves the DOM is decided by `keepMounted` on the portal. - `close`: Closes the navigation menu imperatively when called. |
| align | `"center" \| "start" \| "end"` | `start` | How to align the popup relative to the specified side. |
| closeDelay | `number` | `50` | How long to wait before closing the navigation popup. Specified in milliseconds. |
| defaultValue | `any` | `null` | The uncontrolled value of the item that should be initially selected.  To render a controlled navigation menu, use the `value` prop instead. |
| delay | `number` | `50` | How long to wait before opening the navigation popup. Specified in milliseconds. |
| onOpenChangeComplete | `((open: boolean) => void)` |  | Event handler called after any animations complete when the navigation menu is closed. |
| onValueChange | `((value: any, eventDetails: NavigationMenuRootChangeEventDetails) => void)` |  | Callback fired when the value changes. |
| orientation | `"horizontal" \| "vertical"` | `'horizontal'` | The orientation of the navigation menu. |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, NavigationMenuRootState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |
| value | `any` | `null` | The controlled value of the navigation menu item that should be currently open. When non-nullish, the menu will be open. When nullish, the menu will be closed.  To render an uncontrolled navigation menu, use the `defaultValue` prop instead. |

### NavigationMenuContent

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| keepMounted | `boolean` | `false` | Whether to keep the content mounted in the DOM while the popup is closed. Ensures the content is present during server-side rendering for web crawlers. |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, NavigationMenuContentState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### NavigationMenuIndicator

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, NavigationMenuIconState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### NavigationMenuItem

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, NavigationMenuItemState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |
| value | `any` |  | A unique value that identifies this navigation menu item. If no value is provided, a unique ID will be generated automatically. Use when controlling the navigation menu programmatically. |

### NavigationMenuLink

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| active | `boolean` | `false` | Whether the link is the currently active page. |
| closeOnClick | `boolean` | `false` | Whether to close the navigation menu when the link is clicked. |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, NavigationMenuLinkState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### NavigationMenuList

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, NavigationMenuListState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### NavigationMenuTrigger

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| disabled | `boolean` | `false` | Whether the component should ignore user interaction. |
| nativeButton | `boolean` | `true` | Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`). |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, NavigationMenuTriggerState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### NavigationMenuPositioner

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| align | `"center" \| "start" \| "end"` | `start` | How to align the popup relative to the specified side. |
| alignOffset | `number \| OffsetFunction` | `0` | Additional offset along the alignment axis in pixels. Also accepts a function that returns the offset to read the dimensions of the anchor and positioner elements, along with its side and alignment.  The function takes a `data` object parameter with the following properties: - `data.anchor`: the dimensions of the anchor element with properties `width` and `height`. - `data.positioner`: the dimensions of the positioner element with properties `width` and `height`. - `data.side`: which side of the anchor element the positioner is aligned against. - `data.align`: how the positioner is aligned relative to the specified side. @example ```jsx <Positioner   alignOffset={({ side, align, anchor, positioner }) => {     return side === 'top' \|\| side === 'bottom'       ? anchor.width       : anchor.height;   }} /> ``` |
| anchor | `Element \| VirtualElement \| RefObject<Element \| null> \| (() => Element \| VirtualElement \| null) \| null` |  | An element to position the popup against. By default, the popup will be positioned against the trigger. |
| arrowPadding | `number` | `5` | Minimum distance to maintain between the arrow and the edges of the popup.  Use it to prevent the arrow element from hanging out of the rounded corners of a popup. |
| collisionAvoidance | `CollisionAvoidance` |  | Determines how to handle collisions when positioning the popup.  `side` controls overflow on the preferred placement axis (`top`/`bottom` or `left`/`right`): - `'flip'`: keep the requested side when it fits; otherwise try the opposite side   (`top` and `bottom`, or `left` and `right`). - `'shift'`: never change side; keep the requested side and move the popup within   the clipping boundary so it stays visible. - `'none'`: do not correct side-axis overflow.  `align` controls overflow on the alignment axis (`start`/`center`/`end`): - `'flip'`: keep side, but swap `start` and `end` when the requested alignment overflows. - `'shift'`: keep side and requested alignment, then nudge the popup along the   alignment axis to fit. - `'none'`: do not correct alignment-axis overflow.  `fallbackAxisSide` controls fallback behavior on the perpendicular axis when the preferred axis cannot fit: - `'start'`: allow perpendicular fallback and try the logical start side first   (`top` before `bottom`, or `left` before `right` in LTR). - `'end'`: allow perpendicular fallback and try the logical end side first   (`bottom` before `top`, or `right` before `left` in LTR). - `'none'`: do not fallback to the perpendicular axis.  When `side` is `'shift'`, explicitly setting `align` only supports `'shift'` or `'none'`. If `align` is omitted, it defaults to `'flip'`. @example ```jsx <Positioner   collisionAvoidance={{     side: 'shift',     align: 'shift',     fallbackAxisSide: 'none',   }} /> ``` |
| collisionBoundary | `Boundary` | `'clipping-ancestors'` | An element or a rectangle that delimits the area that the popup is confined to. |
| collisionPadding | `Padding` | `5` | Additional space to maintain from the edge of the collision boundary. |
| disableAnchorTracking | `boolean` | `false` | Whether to disable the popup from tracking any layout shift of its positioning anchor. |
| positionMethod | `"absolute" \| "fixed"` | `'absolute'` | Determines which CSS `position` property to use. |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, NavigationMenuPositionerState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |
| side | `"left" \| "right" \| "top" \| "bottom" \| "inline-end" \| "inline-start"` | `bottom` | Which side of the anchor element to align the popup against. May automatically change to avoid collisions. |
| sideOffset | `number \| OffsetFunction` | `0` | Distance between the anchor and the popup in pixels. Also accepts a function that returns the distance to read the dimensions of the anchor and positioner elements, along with its side and alignment.  The function takes a `data` object parameter with the following properties: - `data.anchor`: the dimensions of the anchor element with properties `width` and `height`. - `data.positioner`: the dimensions of the positioner element with properties `width` and `height`. - `data.side`: which side of the anchor element the positioner is aligned against. - `data.align`: how the positioner is aligned relative to the specified side. @example ```jsx <Positioner   sideOffset={({ side, align, anchor, positioner }) => {     return side === 'top' \|\| side === 'bottom'       ? anchor.height       : anchor.width;   }} /> ``` |
| sticky | `boolean` | `false` | Whether to maintain the popup in the viewport after the anchor element was scrolled out of view. |

