Navigation Menu
View as MarkdownA collection of links and menus for website navigation.
<ui:navigationMenu.root withViewport="{true}">
<ui:navigationMenu.list>
<ui:navigationMenu.item value="products">
<ui:navigationMenu.trigger>Products</ui:navigationMenu.trigger>
</ui:navigationMenu.item>
<ui:navigationMenu.item value="company">
<ui:navigationMenu.trigger>Company</ui:navigationMenu.trigger>
</ui:navigationMenu.item>
<ui:navigationMenu.item value="docs">
<ui:navigationMenu.link href="#">Documentation</ui:navigationMenu.link>
</ui:navigationMenu.item>
</ui:navigationMenu.list>
<ui:navigationMenu.indicator>
<ui:navigationMenu.arrow />
</ui:navigationMenu.indicator>
<ui:navigationMenu.viewportPositioner>
<ui:navigationMenu.viewport>
<ui:navigationMenu.content value="products" class="w-90">
<div class="grid grid-cols-2">
<ui:navigationMenu.link value="products" href="#" class="flex flex-col gap-0.5 !py-2 !px-3">
<span class="font-medium text-sm">Analytics</span>
<span class="text-xs text-muted-foreground">Track and analyze data</span>
</ui:navigationMenu.link>
<ui:navigationMenu.link value="products" href="#" class="flex flex-col gap-0.5 !py-2 !px-3">
<span class="font-medium text-sm">Marketing</span>
<span class="text-xs text-muted-foreground">Grow your audience</span>
</ui:navigationMenu.link>
<ui:navigationMenu.link value="products" href="#" class="flex flex-col gap-0.5 !py-2 !px-3">
<span class="font-medium text-sm">Automation</span>
<span class="text-xs text-muted-foreground">Save time with workflows</span>
</ui:navigationMenu.link>
<ui:navigationMenu.link value="products" href="#" class="flex flex-col gap-0.5 !py-2 !px-3">
<span class="font-medium text-sm">Commerce</span>
<span class="text-xs text-muted-foreground">Sell online with ease</span>
</ui:navigationMenu.link>
</div>
</ui:navigationMenu.content>
<ui:navigationMenu.content value="company" class="w-32">
<div class="grid grid-cols-1">
<ui:navigationMenu.link value="company" href="#">About Us</ui:navigationMenu.link>
<ui:navigationMenu.link value="company" href="#">Blog</ui:navigationMenu.link>
<ui:navigationMenu.link value="company" href="#">Careers</ui:navigationMenu.link>
<ui:navigationMenu.link value="company" href="#">Press</ui:navigationMenu.link>
</div>
</ui:navigationMenu.content>
</ui:navigationMenu.viewport>
</ui:navigationMenu.viewportPositioner>
</ui:navigationMenu.root>
import { mountAll } from 'fluid-primitives';
import { NavigationMenu } from 'fluid-primitives/navigation-menu';
mountAll('navigationMenu', ({ props }) => {
const navigationMenu = new NavigationMenu(props);
navigationMenu.init();
return navigationMenu;
});
Features
- Supports simple inline dropdowns and shared viewport layouts
- Keyboard navigation with arrow keys,
Home, andEnd - Supports trigger-based menus and direct navigation links in the same list
- Animated indicator and shared viewport support
- Supports horizontal and vertical orientation
Installation
typo3 ui:add navigation-menu
Please copy the files manually from GitHub into your project.
Read more about installing Components and Primitives.
Examples
Simple Dropdown
Render navigation items with inline dropdown content.
<ui:navigationMenu.root>
<ui:navigationMenu.list>
<ui:navigationMenu.item value="products">
<ui:navigationMenu.trigger>Products</ui:navigationMenu.trigger>
<ui:navigationMenu.content>
<div class="grid grid-cols-1">
<ui:navigationMenu.link href="#">Overview</ui:navigationMenu.link>
<ui:navigationMenu.link href="#">Features</ui:navigationMenu.link>
<ui:navigationMenu.link href="#">Pricing</ui:navigationMenu.link>
<ui:navigationMenu.link href="#">Changelog</ui:navigationMenu.link>
</div>
</ui:navigationMenu.content>
</ui:navigationMenu.item>
<ui:navigationMenu.item value="company">
<ui:navigationMenu.trigger>Company</ui:navigationMenu.trigger>
<ui:navigationMenu.content>
<div class="grid grid-cols-1">
<ui:navigationMenu.link href="#">About</ui:navigationMenu.link>
<ui:navigationMenu.link href="#">Blog</ui:navigationMenu.link>
<ui:navigationMenu.link href="#">Careers</ui:navigationMenu.link>
<ui:navigationMenu.link href="#">Press</ui:navigationMenu.link>
</div>
</ui:navigationMenu.content>
</ui:navigationMenu.item>
<ui:navigationMenu.item value="docs">
<ui:navigationMenu.link href="#">Documentation</ui:navigationMenu.link>
</ui:navigationMenu.item>
</ui:navigationMenu.list>
</ui:navigationMenu.root>
Links Only
Use the navigation menu as a simple list of links, including a current page link.
<ui:navigationMenu.root>
<ui:navigationMenu.list>
<ui:navigationMenu.item value="home">
<ui:navigationMenu.link href="/" current="{true}">Home</ui:navigationMenu.link>
</ui:navigationMenu.item>
<ui:navigationMenu.item value="docs">
<ui:navigationMenu.link href="/docs">Docs</ui:navigationMenu.link>
</ui:navigationMenu.item>
<ui:navigationMenu.item value="github">
<ui:navigationMenu.link href="/github">GitHub</ui:navigationMenu.link>
</ui:navigationMenu.item>
</ui:navigationMenu.list>
</ui:navigationMenu.root>
With Viewport
Use withViewport="{true}" to render dropdown content inside a shared viewport. This pattern works well for richer header navigation with animated transitions and an indicator.
<ui:navigationMenu.root withViewport="{true}">
<ui:navigationMenu.list>
<ui:navigationMenu.item value="products">
<ui:navigationMenu.trigger>Products</ui:navigationMenu.trigger>
</ui:navigationMenu.item>
<ui:navigationMenu.item value="company">
<ui:navigationMenu.trigger>Company</ui:navigationMenu.trigger>
</ui:navigationMenu.item>
<ui:navigationMenu.item value="docs">
<ui:navigationMenu.link href="#">Documentation</ui:navigationMenu.link>
</ui:navigationMenu.item>
</ui:navigationMenu.list>
<ui:navigationMenu.indicator>
<ui:navigationMenu.arrow />
</ui:navigationMenu.indicator>
<ui:navigationMenu.viewportPositioner>
<ui:navigationMenu.viewport>
<ui:navigationMenu.content value="products" class="w-90">
<div class="grid grid-cols-2">
<ui:navigationMenu.link value="products" href="#" class="flex flex-col gap-0.5 !py-2 !px-3">
<span class="font-medium text-sm">Analytics</span>
<span class="text-xs text-muted-foreground">Track and analyze data</span>
</ui:navigationMenu.link>
<ui:navigationMenu.link value="products" href="#" class="flex flex-col gap-0.5 !py-2 !px-3">
<span class="font-medium text-sm">Marketing</span>
<span class="text-xs text-muted-foreground">Grow your audience</span>
</ui:navigationMenu.link>
<ui:navigationMenu.link value="products" href="#" class="flex flex-col gap-0.5 !py-2 !px-3">
<span class="font-medium text-sm">Automation</span>
<span class="text-xs text-muted-foreground">Save time with workflows</span>
</ui:navigationMenu.link>
<ui:navigationMenu.link value="products" href="#" class="flex flex-col gap-0.5 !py-2 !px-3">
<span class="font-medium text-sm">Commerce</span>
<span class="text-xs text-muted-foreground">Sell online with ease</span>
</ui:navigationMenu.link>
</div>
</ui:navigationMenu.content>
<ui:navigationMenu.content value="company" class="w-32">
<div class="grid grid-cols-1">
<ui:navigationMenu.link value="company" href="#">About Us</ui:navigationMenu.link>
<ui:navigationMenu.link value="company" href="#">Blog</ui:navigationMenu.link>
<ui:navigationMenu.link value="company" href="#">Careers</ui:navigationMenu.link>
<ui:navigationMenu.link value="company" href="#">Press</ui:navigationMenu.link>
</div>
</ui:navigationMenu.content>
</ui:navigationMenu.viewport>
</ui:navigationMenu.viewportPositioner>
</ui:navigationMenu.root>
API Reference
The following tables cover the available props of the Fluid Primitives. For a full list of available client side props and methods, see the Zag.js Machine API.
navigationMenu.root
Provides shared navigation menu state and semantics. Renders a <nav> element.
| Name | Description | Required | Default |
|---|---|---|---|
orientation | Enum\OrientationThe orientation of the navigation menu. | No | Horizontal |
defaultValue | stringThe default value of the navigation menu. Use when you don't want to control the value of the menu. | No | '' |
openDelay | integerThe delay before the menu opens. | No | 200 |
closeDelay | integerThe delay before the menu closes. | No | 300 |
disableHoverTrigger | booleanWhether to disable the hover trigger. | No | - |
disableClickTrigger | booleanWhether to disable the click trigger. | No | - |
disablePointerLeaveClose | booleanWhether to disable the pointer leave close. | No | - |
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
rootId | stringThe root ID of the component, used for hydration and identification. | No | - |
ids | arrayThe IDs of of the component parts for composition. | No | [] |
controlled | booleanIf true, the component is meant to be initialized manually inside another component | No | false |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | navigation-menu |
data-part | root |
data-orientation | The orientation of the navigation-menu |
navigationMenu.list
Groups the top-level navigation items. Renders a <ul> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | navigation-menu |
data-part | list |
data-orientation | The orientation of the list |
navigationMenu.item
Wraps a single navigation item and its related parts. Renders an <li> element.
| Name | Description | Required | Default |
|---|---|---|---|
value | stringThe value of the item. | Yes | - |
disabled | booleanWhether the item is disabled. | No | - |
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | navigation-menu |
data-part | item |
data-value | The value of the item |
data-state | "open" | "closed" |
data-orientation | The orientation of the item |
data-disabled | Present when disabled |
navigationMenu.trigger
Opens and closes the related navigation content. Renders a <button> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | navigation-menu |
data-part | trigger |
data-trigger-proxy-id | |
data-value | The value of the item |
data-state | "open" | "closed" |
data-disabled | Present when disabled |
navigationMenu.triggerProxy
Provides a hidden focus proxy for shared viewport behavior. Renders a <span> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | navigation-menu |
data-part | trigger-proxy |
data-trigger-proxy | |
data-trigger-id |
navigationMenu.link
Renders a navigational link item. Renders an <a> element.
| Name | Description | Required | Default |
|---|---|---|---|
value | stringThe value of the item this link belongs to. By default this is inherited from the parent navigationMenu.item. | No | - |
current | booleanWhether the link is the current page. | No | - |
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | navigation-menu |
data-part | link |
data-value | The value of the item |
data-current | Present when current |
navigationMenu.indicatorTrack
Provides a track for the active-item indicator. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
navigationMenu.indicator
Displays the shared active-item indicator. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | navigation-menu |
data-part | indicator |
data-state | "open" | "closed" |
data-orientation | The orientation of the indicator |
navigationMenu.itemIndicator
Displays an indicator for an open item. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | navigation-menu |
data-part | item-indicator |
data-state | "open" | "closed" |
data-orientation | The orientation of the item |
data-value | The value of the item |
navigationMenu.content
Contains the popup content for a navigation item. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
value | stringThe value of the item this content belongs to. | No | - |
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | navigation-menu |
data-part | content |
data-state | "open" | "closed" |
data-orientation | The orientation of the content |
data-value | The value of the item |
navigationMenu.viewportPositioner
Positions the shared viewport element. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
align | Enum\NavigationMenuAlignPlacement of the viewport for CSS variables `--viewport-x` and `--viewport-y`. | No | Center |
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | navigation-menu |
data-part | viewport-positioner |
data-orientation | The orientation of the viewportpositioner |
data-align |
navigationMenu.viewport
Displays the shared viewport that can host item content. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | navigation-menu |
data-part | viewport |
data-state | "open" | "closed" |
data-orientation | The orientation of the viewport |
data-align |
navigationMenu.viewportProxy
Provides a proxy element used to size and align the viewport. Renders a <span> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
navigationMenu.arrow
Displays a decorative arrow for the indicator or content. Renders a <div> element.
| Name | Description | Required | Default |
|---|---|---|---|
asChild | booleanIf true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. | No | - |
class | stringThe CSS class(es) to be applied to the component. | No | - |
attributes | arrayAdditional attributes that should be rendered on the component where ui:attributes is used. | No | [] |
Rendered data attributes
| Attribute | Description |
|---|---|
data-scope | navigation-menu |
data-part | arrow |
data-orientation | The orientation of the arrow |
Machine JavaScript API
| Name | Type | Description |
|---|---|---|
value | string | null | The current value of the menu |
setValue | (value: string) => void | Sets the value of the menu |
open | boolean | Whether the menu is open |
isViewportRendered | boolean | Whether the viewport is rendered |
getViewportNode | () => HTMLElement | null | Gets the viewport node element |
orientation | Orientation | The orientation of the menu |
reposition | VoidFunction | Function to reposition the viewport |
Accessibility
| Key | Description |
|---|---|
ArrowDown | When focus is on trigger (vertical orientation), moves focus to the next trigger. |
ArrowUp | When focus is on trigger (vertical orientation), moves focus to the previous trigger. |
ArrowRight | When focus is on trigger (horizontal orientation), moves focus to the next trigger. When focus is on content, moves focus to the next link. |
ArrowLeft | When focus is on trigger (horizontal orientation), moves focus to the previous trigger. When focus is on content, moves focus to the previous link. |
Home | When focus is on trigger, moves focus to the first trigger. When focus is on content, moves focus to the first link. |
End | When focus is on trigger, moves focus to the last trigger. When focus is on content, moves focus to the last link. |
Anatomy
<primitives:navigationMenu.root>
<primitives:navigationMenu.list>
<primitives:navigationMenu.item>
<primitives:navigationMenu.trigger />
<primitives:navigationMenu.content>
<primitives:navigationMenu.link />
</primitives:navigationMenu.content>
</primitives:navigationMenu.item>
<primitives:navigationMenu.item>
<primitives:navigationMenu.link />
</primitives:navigationMenu.item>
</primitives:navigationMenu.list>
</primitives:navigationMenu.root>
When using the shared viewport pattern, add the optional viewport-related parts:
<primitives:navigationMenu.root>
<primitives:navigationMenu.list>
<primitives:navigationMenu.item>
<primitives:navigationMenu.trigger />
<primitives:navigationMenu.triggerProxy />
<primitives:navigationMenu.viewportProxy />
</primitives:navigationMenu.item>
</primitives:navigationMenu.list>
<primitives:navigationMenu.indicator>
<primitives:navigationMenu.arrow />
</primitives:navigationMenu.indicator>
<primitives:navigationMenu.viewportPositioner>
<primitives:navigationMenu.viewport>
<primitives:navigationMenu.content>
<primitives:navigationMenu.link />
</primitives:navigationMenu.content>
</primitives:navigationMenu.viewport>
</primitives:navigationMenu.viewportPositioner>
</primitives:navigationMenu.root>