> Native Solid 2 fork. Original documentation and designs © WorkOS; historical posts retain their original context.

# Navigation Menu

A collection of links for navigating websites.

## 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.

## Anatomy

Import all parts and piece them together.

```jsx
import { NavigationMenu } from "@radix-solid/primitives";

export default () => <NavigationMenu.Root>

		<NavigationMenu.List>

			<NavigationMenu.Item>

				<NavigationMenu.Trigger />

				<NavigationMenu.Content>

					<NavigationMenu.Link />

				</NavigationMenu.Content>

			</NavigationMenu.Item>



			<NavigationMenu.Item>

				<NavigationMenu.Link />

			</NavigationMenu.Item>



			<NavigationMenu.Item>

				<NavigationMenu.Trigger />

				<NavigationMenu.Content>

					<NavigationMenu.Sub>

						<NavigationMenu.List />

						<NavigationMenu.Viewport />

					</NavigationMenu.Sub>

				</NavigationMenu.Content>

			</NavigationMenu.Item>



			<NavigationMenu.Indicator />

		</NavigationMenu.List>



		<NavigationMenu.Viewport />

	</NavigationMenu.Root>;
```

## API Reference

### Root

Contains all the parts of a navigation menu.

| Prop                                                                                                                                                        | Type       | Default        |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | -------------- |
| `defaultValue`The value of the menu item that should be active when initially rendered. Use when you do not need to control the value state.                | `string`   | —              |
| `value`The controlled value of the menu item to activate. Should be used in conjunction with `onValueChange`.                                               | `string`   | —              |
| `onValueChange`Event handler called when the value changes.                                                                                                 | `function` | —              |
| `delayDuration`The duration from when the mouse enters a trigger until the content opens.                                                                   | `number`   | `200`          |
| `skipDelayDuration`How much time a user has to enter another trigger without incurring a delay again.                                                       | `number`   | `300`          |
| `dir`The reading direction of the menu when applicable. If omitted, inherits globally from `DirectionProvider` or assumes LTR (left-to-right) reading mode. | `enum`     | —              |
| `orientation`The orientation of the menu.                                                                                                                   | `enum`     | `"horizontal"` |

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

### Sub

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

| Prop                                                                                                                                         | Type       | Default        |
| -------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | -------------- |
| `defaultValue`The value of the menu item that should be active when initially rendered. Use when you do not need to control the value state. | `string`   | —              |
| `value`The controlled value of the sub menu item to activate. Should be used in conjunction with `onValueChange`.                            | `string`   | —              |
| `onValueChange`Event handler called when the value changes.                                                                                  | `function` | —              |
| `orientation`The orientation of the menu.                                                                                                    | `enum`     | `"horizontal"` |

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

### List

Contains the top level menu items.

| Prop                                                                                                                                                                    | Type      | Default |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details. | `boolean` | `false` |

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

### Item

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

| Prop                                                                                                                                                                    | Type      | Default |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details. | `boolean` | `false` |
| `value`A unique value that associates the item with an active value when the navigation menu is controlled. This prop is managed automatically when uncontrolled.       | `string`  | —       |

### Trigger

The button that toggles the content.

| Prop                                                                                                                                                                    | Type      | Default |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details. | `boolean` | `false` |

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

### Content

Contains the content associated with each trigger.

| Prop                                                                                                                                                                                     | Type       | Default |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details.                  | `boolean`  | `false` |
| `onEscapeKeyDown`Event handler called when the escape key is down. It can be prevented by calling `event.preventDefault`.                                                                | `function` | —       |
| `onPointerDownOutside`Event handler called when a pointer event occurs outside the bounds of the component. It can be prevented by calling `event.preventDefault`.                       | `function` | —       |
| `onFocusOutside`Event handler called when focus moves outside the bounds of the component. It can be prevented by calling `event.preventDefault`.                                        | `function` | —       |
| `onInteractOutside`Event handler called when an interaction (pointer or focus event) happens outside the bounds of the component. It can be prevented by calling `event.preventDefault`. | `function` | —       |
| `forceMount`Used to force mounting when more control is needed. Useful when controlling animation with Solid-compatible animation libraries.                                             | `boolean`  | —       |

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

### Link

A navigational link.

| Prop                                                                                                                                                                                                        | Type       | Default |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details.                                     | `boolean`  | `false` |
| `active`Used to identify the link as the currently active page.                                                                                                                                             | `boolean`  | `false` |
| `onSelect`Event handler called when the user selects a link (via mouse or keyboard). Calling `event.preventDefault` in this handler will prevent the navigation menu from closing when selecting that link. | `function` | —       |

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

### Indicator

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

| Prop                                                                                                                                                                    | Type      | Default |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details. | `boolean` | `false` |
| `forceMount`Used to force mounting when more control is needed. Useful when controlling animation with Solid-compatible animation libraries.                            | `boolean` | —       |

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

| CSS Variable                                    | Description                                                                                                               |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `--radix-navigation-menu-indicator-translate-x` | The horizontal offset of the indicator, computed from the active trigger's position. Present when the menu is horizontal. |
| `--radix-navigation-menu-indicator-translate-y` | The vertical offset of the indicator, computed from the active trigger's position. Present when the menu is vertical.     |

### Viewport

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

| Prop                                                                                                                                                                    | Type      | Default |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |
| `asChild`Render through a single-target factory, merging props and behavior with the chosen host. Read our [Composition](../guides/composition) guide for more details. | `boolean` | `false` |
| `forceMount`Used to force mounting when more control is needed. Useful when controlling animation with Solid-compatible animation libraries.                            | `boolean` | —       |

| Data attribute       | Values                       |
| -------------------- | ---------------------------- |
| `[data-state]`       | `"open" \| "closed"`         |
| `[data-orientation]` | `"vertical" \| "horizontal"` |

| CSS Variable                              | Description                                                                      |
| ----------------------------------------- | -------------------------------------------------------------------------------- |
| `--radix-navigation-menu-viewport-width`  | The width of the viewport when visible/hidden, computed from the active content  |
| `--radix-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.

```jsx
<NavigationMenu.Root orientation="vertical">

	<NavigationMenu.List>

		<NavigationMenu.Item>

			<NavigationMenu.Trigger>Item one</NavigationMenu.Trigger>

			<NavigationMenu.Content>Item one content</NavigationMenu.Content>

		</NavigationMenu.Item>

		<NavigationMenu.Item>

			<NavigationMenu.Trigger>Item two</NavigationMenu.Trigger>

			<NavigationMenu.Content>Item Two content</NavigationMenu.Content>

		</NavigationMenu.Item>

	</NavigationMenu.List>

</NavigationMenu.Root>
```

### 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](/primitives/docs/components/navigation-menu#advanced-animation). Tab focus will be maintained automatically.

```jsx
<NavigationMenu.Root>

	<NavigationMenu.List>

		<NavigationMenu.Item>

			<NavigationMenu.Trigger>Item one</NavigationMenu.Trigger>

			<NavigationMenu.Content>Item one content</NavigationMenu.Content>

		</NavigationMenu.Item>

		<NavigationMenu.Item>

			<NavigationMenu.Trigger>Item two</NavigationMenu.Trigger>

			<NavigationMenu.Content>Item two content</NavigationMenu.Content>

		</NavigationMenu.Item>

	</NavigationMenu.List>



	{/* NavigationMenu.Content will be rendered here when active */}

	<NavigationMenu.Viewport />

</NavigationMenu.Root>
```

### 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`.

```jsx
// index.tsx

import { NavigationMenu } from "@radix-solid/primitives";

import "./styles.css";

export default () => <NavigationMenu.Root>

		<NavigationMenu.List>

			<NavigationMenu.Item>

				<NavigationMenu.Trigger>Item one</NavigationMenu.Trigger>

				<NavigationMenu.Content>Item one content</NavigationMenu.Content>

			</NavigationMenu.Item>

			<NavigationMenu.Item>

				<NavigationMenu.Trigger>Item two</NavigationMenu.Trigger>

				<NavigationMenu.Content>Item two content</NavigationMenu.Content>

			</NavigationMenu.Item>



			<NavigationMenu.Indicator class="NavigationMenuIndicator" />

		</NavigationMenu.List>



		<NavigationMenu.Viewport />

	</NavigationMenu.Root>;
```

```css
/* styles.css */

.NavigationMenuIndicator {

	background-color: grey;

}

.NavigationMenuIndicator[data-orientation="horizontal"] {

	height: 3px;

	transition:

		width,

		transform,

		250ms ease;

}
```

### 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`](/primitives/docs/components/tabs) in that one item should always be active, so be sure to assign and set a `defaultValue`.

```jsx
<NavigationMenu.Root>

	<NavigationMenu.List>

		<NavigationMenu.Item>

			<NavigationMenu.Trigger>Item one</NavigationMenu.Trigger>

			<NavigationMenu.Content>Item one content</NavigationMenu.Content>

		</NavigationMenu.Item>

		<NavigationMenu.Item>

			<NavigationMenu.Trigger>Item two</NavigationMenu.Trigger>

			<NavigationMenu.Content>

				<NavigationMenu.Sub defaultValue="sub1">

					<NavigationMenu.List>

						<NavigationMenu.Item value="sub1">

							<NavigationMenu.Trigger>Sub item one</NavigationMenu.Trigger>

							<NavigationMenu.Content>

								Sub item one content

							</NavigationMenu.Content>

						</NavigationMenu.Item>

						<NavigationMenu.Item value="sub2">

							<NavigationMenu.Trigger>Sub item two</NavigationMenu.Trigger>

							<NavigationMenu.Content>

								Sub item two content

							</NavigationMenu.Content>

						</NavigationMenu.Item>

					</NavigationMenu.List>

				</NavigationMenu.Sub>

			</NavigationMenu.Content>

		</NavigationMenu.Item>

	</NavigationMenu.List>

</NavigationMenu.Root>
```

### With client side routing

If you need to use the `Link` component provided by your routing package then we recommend composing with `NavigationMenu.Link` via a custom component. This preserves accessibility and consistent keyboard control. The native example below accepts a reactive `pathname` from your router and marks the matching anchor as active; it does not depend on a framework-specific router. To compose a router's own link host, use a single-target `asChild` factory as described in the [Composition guide](/primitives/docs/guides/composition).

```jsx
import { NavigationMenu } from '@radix-solid/primitives';

import { omit, type ComponentProps } from 'solid-js';

type Props = Extract<ComponentProps<typeof NavigationMenu.Link>, {

  asChild?: false;

}> & {

  pathname: string;

};

export function Link(props: Props) {

  return <NavigationMenu.Link {...omit(props, 'pathname')} active={props.href === props.pathname} class="NavigationMenuLink" />;

}
```

```css
/* styles.css */

.NavigationMenuLink {

	text-decoration: none;

}

.NavigationMenuLink[data-active] {

	text-decoration: "underline";

}
```

### Advanced animation

We expose `--radix-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.

```jsx
// index.tsx

import { NavigationMenu } from "@radix-solid/primitives";

import "./styles.css";

export default () => <NavigationMenu.Root>

		<NavigationMenu.List>

			<NavigationMenu.Item>

				<NavigationMenu.Trigger>Item one</NavigationMenu.Trigger>

				<NavigationMenu.Content class="NavigationMenuContent">

					Item one content

				</NavigationMenu.Content>

			</NavigationMenu.Item>

			<NavigationMenu.Item>

				<NavigationMenu.Trigger>Item two</NavigationMenu.Trigger>

				<NavigationMenu.Content class="NavigationMenuContent">

					Item two content

				</NavigationMenu.Content>

			</NavigationMenu.Item>

		</NavigationMenu.List>



		<NavigationMenu.Viewport class="NavigationMenuViewport" />

	</NavigationMenu.Root>;
```

```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(--radix-navigation-menu-viewport-width);

	height: var(--radix-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 `NavigationMenu.Link` for all navigational links within a menu, this not only applies to the main list but also within any content rendered via `NavigationMenu.Content`. 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](/primitives/docs/components/navigation-menu#with-client-side-routing) for more information on usage with third party routing components.

### Keyboard Interactions

| Key                     | Description                                                                                                                                                                                            |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Space``Enter`          | When focus is on `NavigationMenu.Trigger`, opens the content.                                                                                                                                          |
| `Tab`                   | Moves focus to the next focusable element.                                                                                                                                                             |
| `ArrowDown`             | When `horizontal` and focus is on an open `NavigationMenu.Trigger`, moves focus into `NavigationMenu.Content`. Moves focus to the next `NavigationMenu.Trigger` or `NavigationMenu.Link`.              |
| `ArrowUp`               | Moves focus to the previous `NavigationMenu.Trigger` or `NavigationMenu.Link`.                                                                                                                         |
| `ArrowRight``ArrowLeft` | When `vertical` and focus is on an open `NavigationMenu.Trigger`, moves focus into its `NavigationMenu.Content`. Moves focus to the next / previous `NavigationMenu.Trigger` or `NavigationMenu.Link`. |
| `Home``End`             | Moves focus to the first/last `NavigationMenu.Trigger` or `NavigationMenu.Link`.                                                                                                                       |
| `Esc`                   | Closes open `NavigationMenu.Content` and moves focus to its `NavigationMenu.Trigger`.                                                                                                                  |
