---
title: "Navigation Menu"
description: "A collection of links for navigating websites."
canonical_url: "https://vinicunca.dev/akar/components/navigation-menu"
---
# Navigation Menu

> A collection of links for navigating websites.

```vue [index.vue]
<script setup lang="ts">
import {
  NavigationMenuContent,
  NavigationMenuIndicator,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuRoot,
  NavigationMenuTrigger,
  NavigationMenuViewport,
} from 'akar'
import { ref } from 'vue'
import NavigationMenuListItem from './NavigationMenuListItem.vue'

import './styles.css'

const currentTrigger = ref('')
</script>

<template>
  <div class="akar-demo akar-demo-NavigationMenu">
    <NavigationMenuRoot
        v-model="currentTrigger"
        class="NavigationMenuRoot"
      >
        <NavigationMenuList class="NavigationMenuList">
          <NavigationMenuItem>
            <NavigationMenuTrigger
              class="NavigationMenuTrigger"
            >
              Learn
              <PIcon
                name="i-lucide-chevron-down"
                class="CaretDown"
              />
            </NavigationMenuTrigger>
            <NavigationMenuContent
              class="NavigationMenuContent"
            >
              <ul class="List one">
                <li :style="{ gridRow: 'span 3' }">
                  <NavigationMenuLink as-child>
                    <a
                      class="Callout"
                      href="/"
                    >
                      <img src="https://reka-ui.com/logo.svg">
                      <div class="CalloutHeading">Reka UI</div>
                      <p class="CalloutText">Unstyled, accessible components for Vue.</p>
                    </a>
                  </NavigationMenuLink>
                </li>

                <NavigationMenuListItem
                  href="https://stitches.dev/"
                  title="Stitches"
                >
                  CSS-in-JS with best-in-class developer experience.
                </NavigationMenuListItem>
                <NavigationMenuListItem
                  href="/colors"
                  title="Colors"
                >
                  Beautiful, thought-out palettes with auto dark mode.
                </NavigationMenuListItem>
                <NavigationMenuListItem
                  href="https://lucide.dev/icons/"
                  title="Icons"
                >
                  A crisp set of 15x15 icons, balanced and consistent.
                </NavigationMenuListItem>
              </ul>
            </NavigationMenuContent>
          </NavigationMenuItem>

          <NavigationMenuItem>
            <NavigationMenuTrigger
              class="NavigationMenuTrigger"
            >
              Overview
              <PIcon
                name="i-lucide-chevron-down"
                class="CaretDown"
              />
            </NavigationMenuTrigger>
            <NavigationMenuContent class="NavigationMenuContent">
              <ul class="List two">
                <NavigationMenuListItem
                  title="Introduction"
                  href="/docs/primitives/overview/introduction"
                >
                  Build high-quality, accessible design systems and web apps.
                </NavigationMenuListItem>
                <NavigationMenuListItem
                  title="Getting started"
                  href="/docs/primitives/overview/getting-started"
                >
                  A quick tutorial to get you up and running with Reka UI.
                </NavigationMenuListItem>
                <NavigationMenuListItem
                  title="Styling"
                  href="/docs/primitives/guides/styling"
                >
                  Unstyled and compatible with any styling solution.
                </NavigationMenuListItem>
                <NavigationMenuListItem
                  title="Animation"
                  href="/docs/primitives/guides/animation"
                >
                  Use CSS keyframes or any animation library of your choice.
                </NavigationMenuListItem>
                <NavigationMenuListItem
                  title="Accessibility"
                  href="/docs/primitives/overview/accessibility"
                >
                  Tested in a range of browsers and assistive technologies.
                </NavigationMenuListItem>
                <NavigationMenuListItem
                  title="Releases"
                  href="/docs/primitives/overview/releases"
                >
                  Reka UI releases and their changelogs.
                </NavigationMenuListItem>
              </ul>
            </NavigationMenuContent>
          </NavigationMenuItem>

          <NavigationMenuItem>
            <NavigationMenuLink
              class="NavigationMenuLink"
              href="https://github.com/unovue/reka-ui"
            >
              Github
            </NavigationMenuLink>
          </NavigationMenuItem>

          <NavigationMenuIndicator
            class="NavigationMenuIndicator"
          >
            <div class="Arrow" />
          </NavigationMenuIndicator>
        </NavigationMenuList>

        <div class="ViewportPosition">
          <NavigationMenuViewport
            class="NavigationMenuViewport"
          />
        </div>
      </NavigationMenuRoot>
  </div>
</template>
```

```css [styles.css]
@import '../_colors/black-alpha.css';
@import '../_colors/indigo.css';
@import '../_colors/mauve.css';
@import '../_colors/green.css';
@import '../_colors/grass.css';

@scope (.akar-demo-NavigationMenu) {
/* reset */
button,
p {
  all: unset;
}

.NavigationMenuRoot {
  position: relative;
  display: flex;
  justify-content: center;
  width: 100vw;
  z-index: 1;
}

.NavigationMenuList {
  display: flex;
  justify-content: center;
  background-color: white;
  padding: 4px;
  border-radius: 6px;
  list-style: none;
  box-shadow: 0 2px 10px var(--black-a7);
  margin: 0;
}

.NavigationMenuTrigger,
.NavigationMenuLink {
  padding: 8px 12px;
  outline: none;
  user-select: none;
  font-weight: 500;
  line-height: 1;
  border-radius: 4px;
  font-size: 15px;
  color: var(--grass-11);
}
.NavigationMenuTrigger:focus,
.NavigationMenuLink:focus {
  box-shadow: 0 0 0 2px var(--grass-7);
}
.NavigationMenuTrigger:hover,
.NavigationMenuLink:hover {
  background-color: var(--grass-3);
}

.NavigationMenuTrigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2px;
}

.NavigationMenuLink {
  display: block;
  text-decoration: none;
  font-size: 15px;
  line-height: 1;
}

.NavigationMenuContent {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  animation-duration: 250ms;
  animation-timing-function: ease;
}
.NavigationMenuContent[data-motion='from-start'] {
  animation-name: enterFromLeft;
}
.NavigationMenuContent[data-motion='from-end'] {
  animation-name: enterFromRight;
}
.NavigationMenuContent[data-motion='to-start'] {
  animation-name: exitToLeft;
}
.NavigationMenuContent[data-motion='to-end'] {
  animation-name: exitToRight;
}
@media only screen and (min-width: 600px) {
  .NavigationMenuContent {
    width: auto;
  }
}

.NavigationMenuIndicator {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  height: 10px;
  top: 100%;
  overflow: hidden;
  z-index: 1;
  transition: width, transform 250ms ease;
}
.NavigationMenuIndicator[data-state='visible'] {
  animation: fadeIn 200ms ease;
}
.NavigationMenuIndicator[data-state='hidden'] {
  animation: fadeOut 200ms ease;
}

.NavigationMenuViewport {
  position: relative;
  transform-origin: top center;
  margin-top: 10px;
  width: 100%;
  background-color: white;
  border-radius: 6px;
  overflow: hidden;
  box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px;
  height: var(--akar-navigation-menu-viewport-height);
  transition: width, height, 300ms ease;
}
.NavigationMenuViewport[data-state='open'] {
  animation: scaleIn 200ms ease;
}
.NavigationMenuViewport[data-state='closed'] {
  animation: scaleOut 200ms ease;
}
@media only screen and (min-width: 600px) {
  .NavigationMenuViewport {
    width: var(--akar-navigation-menu-viewport-width);
  }
}

.List {
  display: grid;
  padding: 22px;
  margin: 0;
  column-gap: 10px;
  list-style: none;
}
@media only screen and (min-width: 600px) {
  .List.one {
    width: 500px;
    grid-template-columns: 0.75fr 1fr;
  }
  .List.two {
    width: 600px;
    grid-auto-flow: column;
    grid-template-rows: repeat(3, 1fr);
  }
}

.ListItemLink {
  display: block;
  outline: none;
  text-decoration: none;
  user-select: none;
  padding: 12px;
  border-radius: 6px;
  font-size: 15px;
  line-height: 1;
}
.ListItemLink:focus {
  box-shadow: 0 0 0 2px var(--grass-7);
}
.ListItemLink:hover {
  background-color: var(--mauve-3);
}

.ListItemHeading {
  font-weight: 500;
  line-height: 1.2;
  margin-bottom: 5px;
  color: var(--grass-12);
}

.ListItemText {
  color: var(--mauve-11);
  line-height: 1.4;
  font-weight: initial;
}

.Callout {
  display: flex;
  justify-content: flex-end;
  flex-direction: column;
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, var(--green-9) 0%, var(--indigo-9) 100%);
  border-radius: 6px;
  padding: 25px;
  text-decoration: none;
  outline: none;
  user-select: none;
}
.Callout:focus {
  box-shadow: 0 0 0 2px var(--grass-7);
}

.CalloutHeading {
  color: white;
  font-size: 18px;
  font-weight: 500;
  line-height: 1.2;
  margin-top: 16px;
  margin-bottom: 7px;
}

.CalloutText {
  color: var(--mauve-4);
  font-size: 14px;
  line-height: 1.3;
}

.ViewportPosition {
  position: absolute;
  display: flex;
  justify-content: center;
  width: 100%;
  top: 100%;
  left: 0;
  perspective: 2000px;
}

.CaretDown {
  position: relative;
  color: var(--grass-10);
  top: 1px;
  transition: transform 250ms ease;
}
[data-state='open'] > .CaretDown {
  transform: rotate(-180deg);
}

.Arrow {
  position: relative;
  top: 70%;
  background-color: white;
  width: 10px;
  height: 10px;
  transform: rotate(45deg);
  border-top-left-radius: 2px;
}

@keyframes enterFromRight {
  from {
    opacity: 0;
    transform: translateX(200px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes enterFromLeft {
  from {
    opacity: 0;
    transform: translateX(-200px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes exitToRight {
  from {
    opacity: 1;
    transform: translateX(0);
  }
  to {
    opacity: 0;
    transform: translateX(200px);
  }
}

@keyframes exitToLeft {
  from {
    opacity: 1;
    transform: translateX(0);
  }
  to {
    opacity: 0;
    transform: translateX(-200px);
  }
}

@keyframes scaleIn {
  from {
    opacity: 0;
    transform: rotateX(-30deg) scale(0.9);
  }
  to {
    opacity: 1;
    transform: rotateX(0deg) scale(1);
  }
}

@keyframes scaleOut {
  from {
    opacity: 1;
    transform: rotateX(0deg) scale(1);
  }
  to {
    opacity: 0;
    transform: rotateX(-10deg) scale(0.95);
  }
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
}
```

## Features

- Can be controlled or uncontrolled.
- Flexible layout structure with managed tab focus.
- Supports submenus.
- Optional active item indicator.
- Full keyboard navigation.
- Exposes CSS variables for advanced animation.
- Supports custom timings.

## Installation

Install the component from your command line.

```bash [pnpm]
pnpm add akar
```

```bash [yarn]
yarn add akar
```

```bash [npm]
npm install akar
```

```bash [bun]
bun add akar
```

## Anatomy

Import all parts and piece them together.

```vue
<script setup lang="ts">
import {
  NavigationMenuContent,
  NavigationMenuIndicator,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuRoot,
  NavigationMenuSub,
  NavigationMenuTrigger,
  NavigationMenuViewport,
} from 'akar';
</script>

<template>
  <NavigationMenuRoot>
    <NavigationMenuList>
      <NavigationMenuItem>
        <NavigationMenuTrigger />
        <NavigationMenuContent>
          <NavigationMenuLink />
        </NavigationMenuContent>
      </NavigationMenuItem>

      <NavigationMenuItem>
        <NavigationMenuLink />
      </NavigationMenuItem>

      <NavigationMenuItem>
        <NavigationMenuTrigger />
        <NavigationMenuContent>
          <NavigationMenuSub>
            <NavigationMenuList />
            <NavigationMenuViewport />
          </NavigationMenuSub>
        </NavigationMenuContent>
      </NavigationMenuItem>

      <NavigationMenuIndicator />
    </NavigationMenuList>

    <NavigationMenuViewport />
  </NavigationMenuRoot>
</template>
```

## API Reference

### Root

Contains all the parts of a navigation menu.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"nav"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `defaultValue` |  | `string` | The value of the menu item that should be active when initially rendered.<br><br>Use when you do not need to control the value state. |
| `delayDuration` | `200` | `number` | The duration from when the pointer enters the trigger until the tooltip gets opened. |
| `dir` |  | `"ltr" \| "rtl"` | The reading direction of the combobox when applicable.<br><br> If omitted, inherits globally from `ConfigProvider` or assumes LTR (left-to-right) reading mode. |
| `disableClickTrigger` | `false` | `boolean` | If `true`, menu cannot be open by click on trigger |
| `disableHoverTrigger` | `false` | `boolean` | If `true`, menu cannot be open by hover on trigger |
| `disablePointerLeaveClose` | `false` | `boolean` | If `true`, menu will not close during pointer leave event |
| `modelValue` |  | `string` | The controlled value of the menu item to activate. Can be used as `v-model`. |
| `orientation` | `"horizontal"` | `"vertical" \| "horizontal"` | The orientation of the menu. |
| `skipDelayDuration` | `300` | `number` | How much time a user has to enter another trigger without incurring a delay again. |
| `unmountOnHide` | `true` | `boolean` | When `true`, the element will be unmounted on closed state. |

**Events**

| Event | Payload | Description |
| --- | --- | --- |
| `update:modelValue` | `value: string` | Event handler called when the value changes. |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `modelValue` | `string` | Current input values |

[NavigationMenuRoot.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/NavigationMenu/NavigationMenuRoot.vue)

| Data attribute | Value |
| --- | --- |
| `[data-orientation]` | "vertical" \\| "horizontal" |

### Sub

Signifies a submenu. Use it in place of the root part when nested to create a submenu.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `defaultValue` |  | `string` | The value of the menu item that should be active when initially rendered.<br><br>Use when you do not need to control the value state. |
| `modelValue` |  | `string` | The controlled value of the sub menu item to activate. Can be used as `v-model`. |
| `orientation` | `"horizontal"` | `"vertical" \| "horizontal"` | The orientation of the menu. |

**Events**

| Event | Payload | Description |
| --- | --- | --- |
| `update:modelValue` | `value: string` | Event handler called when the value changes. |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `modelValue` | `string` | Current input values |

[NavigationMenuSub.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/NavigationMenu/NavigationMenuSub.vue)

| Data attribute | Value |
| --- | --- |
| `[data-orientation]` | "vertical" \\| "horizontal" |

### List

Contains the top level menu items.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"ul"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |

[NavigationMenuList.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/NavigationMenu/NavigationMenuList.vue)

| Data attribute | Value |
| --- | --- |
| `[data-orientation]` | "vertical" \\| "horizontal" |

### Item

A top level menu item, contains a link or trigger with content combination.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"li"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `value` |  | `string` | A unique value that associates the item with an active value when the navigation menu is controlled.<br><br> This prop is managed automatically when uncontrolled. |

[NavigationMenuItem.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/NavigationMenu/NavigationMenuItem.vue)

### Trigger

The button that toggles the content.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"button"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `disabled` |  | `boolean` | When `true`, prevents the user from interacting with item |

[NavigationMenuTrigger.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/NavigationMenu/NavigationMenuTrigger.vue)

| Data attribute | Value |
| --- | --- |
| `[data-state]` | "open" \\| "closed" |
| `[data-disabled]` | Present when disabled |

### Content

Contains the content associated with each trigger.

> [!NOTE]
> 
> Defer mounting with `forceMount` / [`Presence`](https://vinicunca.dev/akar/utilities/presence). See the [animation guide](https://vinicunca.dev/akar/guides/animation).

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `disableOutsidePointerEvents` |  | `boolean` | When `true`, hover/focus/click interactions will be disabled on elements outside<br>the `DismissableLayer`. Users will need to click twice on outside elements to<br>interact with them: once to close the `DismissableLayer`, and again to trigger the element. |
| `forceMount` |  | `boolean` | Used to force mounting when more control is needed. Useful when<br>controlling animation with Vue animation libraries. |

**Events**

| Event | Payload | Description |
| --- | --- | --- |
| `escapeKeyDown` | `event: KeyboardEvent` | Event handler called when the escape key is down.<br>Can be prevented. |
| `focusOutside` | `event: FocusOutsideEvent` | Event handler called when the focus moves outside of the `DismissableLayer`.<br>Can be prevented. |
| `interactOutside` | `event: PointerDownOutsideEvent \| FocusOutsideEvent` | Event handler called when an interaction happens outside the `DismissableLayer`.<br>Specifically, when a `pointerdown` event happens outside or focus moves outside of it.<br>Can be prevented. |
| `pointerDownOutside` | `event: PointerDownOutsideEvent` | Event handler called when a `pointerdown` event happens outside of the `DismissableLayer`.<br>Can be prevented. |

[NavigationMenuContent.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/NavigationMenu/NavigationMenuContent.vue)

| Data attribute | Value |
| --- | --- |
| `[data-state]` | "open" \\| "closed" |
| `[data-motion]` | "to-start" \\| "to-end" \\| "from-start" \\| "from-end" |
| `[data-orientation]` | "vertical" \\| "horizontal" |

### Link

A navigational link.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `active` |  | `boolean` | Used to identify the link as the currently active page. |
| `as` | `"a"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |

**Events**

| Event | Payload | Description |
| --- | --- | --- |
| `select` | `payload: CustomEvent<{ originalEvent: Event; }>` | Event handler called when the user selects a link (via mouse or keyboard).<br><br>Calling `event.preventDefault` in this handler will prevent the navigation menu from closing when selecting that link. |

[NavigationMenuLink.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/NavigationMenu/NavigationMenuLink.vue)

| Data attribute | Value |
| --- | --- |
| `[data-active]` | Present when active |

### Indicator

An optional indicator element that renders below the list, is used to highlight the currently active trigger.

> [!NOTE]
> 
> Defer mounting with `forceMount` / [`Presence`](https://vinicunca.dev/akar/utilities/presence). See the [animation guide](https://vinicunca.dev/akar/guides/animation).

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `forceMount` |  | `boolean` | Used to force mounting when more control is needed. Useful when<br>controlling animation with Vue animation libraries. |

[NavigationMenuIndicator.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/NavigationMenu/NavigationMenuIndicator.vue)

| Data attribute | Value |
| --- | --- |
| `[data-state]` | "visible" \\| "hidden" |
| `[data-orientation]` | "vertical" \\| "horizontal" |

| CSS variable | Description |
| --- | --- |
| `--akar-navigation-menu-indicator-size` | The size of the indicator. |
| `--akar-navigation-menu-indicator-position` | The position of the indicator |

### Viewport

An optional viewport element that is used to render active content outside of the list.

> [!NOTE]
> 
> Defer mounting with `forceMount` / [`Presence`](https://vinicunca.dev/akar/utilities/presence). See the [animation guide](https://vinicunca.dev/akar/guides/animation).

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `align` | `"center"` | `"start" \| "center" \| "end"` | Placement of the viewport for css variables `(--akar-navigation-menu-viewport-left, --akar-navigation-menu-viewport-top)`. |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `forceMount` |  | `boolean` | Used to force mounting when more control is needed. Useful when<br>controlling animation with Vue animation libraries. |

[NavigationMenuViewport.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/NavigationMenu/NavigationMenuViewport.vue)

| Data attribute | Value |
| --- | --- |
| `[data-state]` | "visible" \\| "hidden" |
| `[data-orientation]` | "vertical" \\| "horizontal" |

| CSS variable | Description |
| --- | --- |
| `--akar-navigation-menu-viewport-width` | The width of the viewport when visible/hidden, computed from the active content |
| `--akar-navigation-menu-viewport-height` | The height of the viewport when visible/hidden, computed from the active content |

## Examples

### Vertical

You can create a vertical menu by using the `orientation` prop.

```vue
<script setup lang="ts">
import {
  NavigationMenuContent,
  NavigationMenuIndicator,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuRoot,
  NavigationMenuSub,
  NavigationMenuTrigger,
  NavigationMenuViewport,
} from 'akar'
</script>

<template>
  <NavigationMenuRoot orientation="vertical">
    <NavigationMenuList>
      <NavigationMenuItem>
        <NavigationMenuTrigger>Item one</NavigationMenuTrigger>
        <NavigationMenuContent>Item one content</NavigationMenuContent>
      </NavigationMenuItem>
      <NavigationMenuItem>
        <NavigationMenuTrigger>Item two</NavigationMenuTrigger>
        <NavigationMenuContent>Item Two content</NavigationMenuContent>
      </NavigationMenuItem>
    </NavigationMenuList>
  </NavigationMenuRoot>
</template>
```

### Flexible layouts

Use the `Viewport` part when you need extra control over where `Content` is rendered. This can be helpful when your design
requires an adjusted DOM structure or if you need flexibility to achieve [advanced animation](https://vinicunca.dev/akar/components/navigation-menu#advanced-animation).
Tab focus will be maintained automatically.

```vue
<script setup lang="ts">
import {
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuList,
  NavigationMenuRoot,
  NavigationMenuTrigger,
  NavigationMenuViewport,
} from 'akar'
</script>

<template>
  <NavigationMenuRoot>
    <NavigationMenuList>
      <NavigationMenuItem>
        <NavigationMenuTrigger>Item one</NavigationMenuTrigger>
        <NavigationMenuContent>Item one content</NavigationMenuContent>
      </NavigationMenuItem>
      <NavigationMenuItem>
        <NavigationMenuTrigger>Item two</NavigationMenuTrigger>
        <NavigationMenuContent>Item two content</NavigationMenuContent>
      </NavigationMenuItem>
    </NavigationMenuList>

    <!-- NavigationMenuContent will be rendered here when active  -->
    <NavigationMenuViewport />
  </NavigationMenuRoot>
</template>
```

### With indicator

You can use the optional `Indicator` part to highlight the currently active `Trigger`, this is useful when you want to provide
an animated visual cue such as an arrow or highlight to accompany the `Viewport`.

```vue
<script setup lang="ts">
import {
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuList,
  NavigationMenuRoot,
  NavigationMenuTrigger,
  NavigationMenuViewport,
} from 'akar'
</script>

<template>
  <NavigationMenuRoot>
    <NavigationMenuList>
      <NavigationMenuItem>
        <NavigationMenuTrigger>Item one</NavigationMenuTrigger>
        <NavigationMenuContent>Item one content</NavigationMenuContent>
      </NavigationMenuItem>
      <NavigationMenuItem>
        <NavigationMenuTrigger>Item two</NavigationMenuTrigger>
        <NavigationMenuContent>Item two content</NavigationMenuContent>
      </NavigationMenuItem>

      <NavigationMenuIndicator class="NavigationMenuIndicator" />
    </NavigationMenuList>

    <NavigationMenuViewport />
  </NavigationMenuRoot>
</template>
```

```css
/* styles.css */
.NavigationMenuIndicator {
  background-color: grey;
  position: absolute;
  transition:
    width,
    transform,
    250ms ease;
}

.NavigationMenuIndicator[data-orientation='horizontal'] {
  left: 0;
  height: 3px;
  transform: translateX(var(--akar-navigation-menu-indicator-position));
  width: var(--akar-navigation-menu-indicator-size);
}
```

### With submenus

Create a submenu by nesting your `NavigationMenu` and using the `Sub` part in place of its `Root`.
Submenus work differently to `Root` navigation menus and are similar to [`Tabs`](https://vinicunca.dev/akar/components/tabs) in that one item should always be active, so be
sure to assign and set a `defaultValue`.

```vue
<script setup lang="ts">
import {
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuList,
  NavigationMenuRoot,
  NavigationMenuSub,
  NavigationMenuTrigger,
  NavigationMenuViewport,
} from 'akar'
</script>

<template>
  <NavigationMenuRoot>
    <NavigationMenuList>
      <NavigationMenuItem>
        <NavigationMenuTrigger>Item one</NavigationMenuTrigger>
        <NavigationMenuContent>Item one content</NavigationMenuContent>
      </NavigationMenuItem>
      <NavigationMenuItem>
        <NavigationMenuTrigger>Item two</NavigationMenuTrigger>
        <NavigationMenuContent>
          <NavigationMenuSub default-value="sub1">
            <NavigationMenuList>
              <NavigationMenuItem value="sub1">
                <NavigationMenuTrigger>Sub item one</NavigationMenuTrigger>
                <NavigationMenuContent> Sub item one content </NavigationMenuContent>
              </NavigationMenuItem>
              <NavigationMenuItem value="sub2">
                <NavigationMenuTrigger>Sub item two</NavigationMenuTrigger>
                <NavigationMenuContent> Sub item two content </NavigationMenuContent>
              </NavigationMenuItem>
            </NavigationMenuList>
          </NavigationMenuSub>
        </NavigationMenuContent>
      </NavigationMenuItem>
    </NavigationMenuList>
  </NavigationMenuRoot>
</template>
```

### With client side routing

If you need to use the `RouterLink` component provided by your routing package then we recommend adding `asChild="true"` to `NavigationMenuLink`, or setting `as="RouterLink"`.
This will ensure accessibility and consistent keyboard control is maintained:

```vue
<script setup lang="ts">
import { NavigationMenuItem, NavigationMenuList, NavigationMenuRoot } from 'akar'

// RouterLink should be injected by default if using `vue-router`
</script>

<template>
  <NavigationMenuRoot>
    <NavigationMenuList>
      <NavigationMenuItem>
        <NavigationMenuLink as-child>
          <RouterLink to="/">
            Home
          </RouterLink>
          <NavigationMenuLink />
        </NavigationMenuLink>
      </NavigationMenuItem>
      <NavigationMenuItem>
        <NavigationMenuLink
          :as="RouterLink"
          to="/about"
        >
          About
        </NavigationMenuLink>
      </NavigationMenuItem>
    </NavigationMenuList>
  </NavigationMenuRoot>
</template>
```

### Advanced animation

We expose `--akar-navigation-menu-viewport-[width|height]` and `data-motion['from-start'|'to-start'|'from-end'|'to-end']` attributes to allow you to animate `Viewport` size and `Content` position based on the enter/exit direction.

Combining these with `position: absolute;` allows you to create smooth overlapping animation effects when moving between items.

```vue
<script setup lang="ts">
import {
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuList,
  NavigationMenuRoot,
  NavigationMenuTrigger,
  NavigationMenuViewport,
} from 'akar'
</script>

<template>
  <NavigationMenuRoot>
    <NavigationMenuList>
      <NavigationMenuItem>
        <NavigationMenuTrigger>Item one</NavigationMenuTrigger>
        <NavigationMenuContent class="NavigationMenuContent">
          Item one content
        </NavigationMenuContent>
      </NavigationMenuItem>
      <NavigationMenuItem>
        <NavigationMenuTrigger>Item two</NavigationMenuTrigger>
        <NavigationMenuContent class="NavigationMenuContent">
          Item two content
        </NavigationMenuContent>
      </NavigationMenuItem>
    </NavigationMenuList>

    <NavigationMenuViewport class="NavigationMenuViewport" />
  </NavigationMenuRoot>
</template>
```

```css
/* styles.css */
.NavigationMenuContent {
  position: absolute;
  top: 0;
  left: 0;
  animation-duration: 250ms;
  animation-timing-function: ease;
}
.NavigationMenuContent[data-motion="from-start"] {
  animation-name: enterFromLeft;
}
.NavigationMenuContent[data-motion="from-end"] {
  animation-name: enterFromRight;
}
.NavigationMenuContent[data-motion="to-start"] {
  animation-name: exitToLeft;
}
.NavigationMenuContent[data-motion="to-end"] {
  animation-name: exitToRight;
}

.NavigationMenuViewport {
  position: relative;
  width: var(--akar-navigation-menu-viewport-width);
  height: var(--akar-navigation-menu-viewport-height);
  transition: width, height, 250ms ease;
}

@keyframes enterFromRight {
  from {
    opacity: 0;
    transform: translateX(200px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes enterFromLeft {
  from {
    opacity: 0;
    transform: translateX(-200px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes exitToRight {
  from {
    opacity: 1;
    transform: translateX(0);
  }
  to {
    opacity: 0;
    transform: translateX(200px);
  }
}

@keyframes exitToLeft {
  from {
    opacity: 1;
    transform: translateX(0);
  }
  to {
    opacity: 0;
    transform: translateX(-200px);
  }
}
```

## Accessibility

Adheres to the [`navigation` role requirements](https://www.w3.org/TR/wai-aria-1.2/#navigation).

### Differences to menubar

`NavigationMenu` should not be confused with `menubar`, although this primitive shares the name `menu` in the colloquial sense to refer to a set of navigation links, it does not use the WAI-ARIA `menu` role.
This is because `menu` and `menubars` behave like native operating system menus most commonly found in desktop application windows, as such they feature complex functionality like composite focus management and first-character navigation.

These features are often considered [unnecessary for website navigation](https://github.com/w3c/aria-practices/issues/353) and at worst can confuse users who are familiar with established website patterns.

See the W3C [Disclosure Navigation Menu](https://w3c.github.io/aria-practices/examples/disclosure/disclosure-navigation.html) example for more information.

### Link usage and aria-current

It's important to use `NavigationMenuLink` for all navigational links within a menu, this not only applies to the main list
but also within any content rendered via `NavigationMenuContent`. This will ensure consistent keyboard interactions and accessibility
while also giving access to the `active` prop for setting `aria-current` and the active styles.
See [this example](https://vinicunca.dev/akar/components/navigation-menu#with-client-side-routing) for more information on usage with third party routing components.

### Keyboard Interactions

| Key | Description |
| --- | --- |

```text
Moves focus to the next <code>NavigationMenuTrigger</code> or
      <code>NavigationMenuLink</code>.

  `,
},
{
  keys: ['ArrowUp'],
  description: `

      Moves focus to the previous <code>NavigationMenuTrigger</code> or
      <code>NavigationMenuLink</code>.

  `,
},
{
  keys: ['ArrowRight', 'ArrowLeft'],
  description: `

      When <code>vertical</code> and focus is on an open
      <code>NavigationMenuTrigger</code>, moves focus into its
      <code>NavigationMenuContent</code>.
      <br />
      Moves focus to the next / previous <code> NavigationMenuTrigger </code> or <code>NavigationMenuLink</code>.

  `,
},
{
  keys: ['Home', 'End'],
  description: `

      Moves focus to the first/last <code>NavigationMenu.Trigger</code> or
      <code>NavigationMenu.Link</code>.

  `,
},
{
  keys: ['Esc'],
  description: `

      Closes open <code>NavigationMenu.Content</code> and moves focus to its
      <code>NavigationMenu.Trigger</code>.

  `,
},
```

]"
/>

---

- [ARIA](https://www.w3.org/TR/wai-aria/#navigation)
- [GitHub](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/NavigationMenu)
- [npm](https://www.npmjs.com/package/akar)


## Sitemap

See the full [sitemap](https://vinicunca.dev/sitemap.md) for all pages.
