# Navigation menu

Host: Base UI. Path: transitions. Preset: `fade`. Built against [@base-ui/react 1.5.0](https://www.npmjs.com/package/@base-ui/react/v/1.5.0).

Base UI does not reuse the data-motion name, so unlike Radix there is no collision to guard against.

The page this file mirrors mounts the component twice, once with the attribute and once without, so the only difference between the two is the library.

Upstream documentation: [Base UI documentation](https://base-ui.com/react/components/navigation-menu)

The same component in other hosts: [Radix UI](/radix/navigation-menu.md).

## Where the attribute goes

The parts this demo composes, and the value each one carries. Everything inside an animated part is that part's content, so the tree stops there.

```text
NavigationMenu.Root
  NavigationMenu.List
    NavigationMenu.Item
      NavigationMenu.Trigger
      NavigationMenu.Content
        NavigationMenu.Link
  NavigationMenu.Portal
    NavigationMenu.Positioner
      NavigationMenu.Popup  data-motion="fade"
```

## How the match works

| Step | Value |
| --- | --- |
| host writes | `data-open / data-closed, plus data-ending-style` |
| easeful matches | `[data-motion~="fade"][data-ending-style]` |
| what runs | `transition: opacity 150ms` |
| you write | `<NavigationMenu.Content data-motion="fade" />` |

## Every value that works here

Every value the manifest allows on this host, single presets and the pairs that compose. The first is what this component ships with. Both stages are the same component, so anything that changes between them is the attribute.

| Value | Link |
| --- | --- |
| `fade` | the default |
| `scale-fade` | [scale-fade](/base-ui/navigation-menu#motion=scale-fade) |
| `slide-up` | [slide-up](/base-ui/navigation-menu#motion=slide-up) |
| `fade slide-up` | [fade slide-up](/base-ui/navigation-menu#motion=fade%20slide-up) |
| `scale-fade slide-up` | [scale-fade slide-up](/base-ui/navigation-menu#motion=scale-fade%20slide-up) |

## Source

`apps/docs/components/demos/base-ui/navigation-menu.tsx`

```tsx
"use client"

import { NavigationMenu } from "@base-ui/react/navigation-menu"
import type { DemoProps } from "@/components/demos/props"

/* Base UI splits the navigation menu differently from Radix: the shared popup
 * is positioned outside the list, and the Viewport inside it is what the active
 * Content renders into. The animated element is therefore the Popup, not the
 * Content. */
export function BaseUiNavigationMenu({ motion }: DemoProps) {
  return (
    <NavigationMenu.Root className="navmenu">
      <NavigationMenu.List className="navmenu__list">
        <NavigationMenu.Item>
          <NavigationMenu.Trigger className="tab">Products</NavigationMenu.Trigger>
          <NavigationMenu.Content className="navmenu__content">
            <NavigationMenu.Link className="navmenu__link" href="#products">
              Motion presets
            </NavigationMenu.Link>
            <NavigationMenu.Link className="navmenu__link" href="#products">
              Host adapters
            </NavigationMenu.Link>
          </NavigationMenu.Content>
        </NavigationMenu.Item>
        <NavigationMenu.Item>
          <NavigationMenu.Trigger className="tab">Company</NavigationMenu.Trigger>
          <NavigationMenu.Content className="navmenu__content">
            <NavigationMenu.Link className="navmenu__link" href="#company">
              About
            </NavigationMenu.Link>
            <NavigationMenu.Link className="navmenu__link" href="#company">
              Changelog
            </NavigationMenu.Link>
          </NavigationMenu.Content>
        </NavigationMenu.Item>
      </NavigationMenu.List>
      <NavigationMenu.Portal>
        <NavigationMenu.Positioner sideOffset={8} collisionPadding={16}>
          <NavigationMenu.Popup className="navmenu__popup" data-motion={motion}>
            <NavigationMenu.Viewport />
          </NavigationMenu.Popup>
        </NavigationMenu.Positioner>
      </NavigationMenu.Portal>
    </NavigationMenu.Root>
  )
}
```
