Navigation Menu
A site or app navigation bar with links and panels of links. Built on Radix Navigation Menu. It is separate from CK-UI's Navbar and can be placed inside it.
Installation
Add Navigation Menu to your project with the CK-UI CLI. It copies the source into your project, so the code is yours to change.
- Adds
NavigationMenu.tsxto your CK-UI folder (src/components/ck-ui by default)- Installs
@radix-ui/react-navigation-menureact-iconsif your project does not have them yet
First time with CK-UI in this project? Run npx ck-ui-cli@latest init once before adding components. The installation guide explains what it sets up.
Manual installationInstall the packages and copy the files yourself.
Install the following dependencies
Run these commands in your terminal to install the required packages
Create or update your NavigationMenu component
Copy this code to create your NavigationMenu component
Test Your Component
- 1. Add the component to a test page
- 2. Check all props and variants work as expected
- 3. Verify responsive behavior
- 4. Test with different content/data
- 5. Ensure accessibility features work correctly
External Links
external opens the link in a new tab with rel="noopener noreferrer", an icon and screen-reader text.
Without Viewport
By default panels share one animated viewport under the bar. viewport={false} positions each panel under its own trigger.
Mobile
- Triggers open on tap; panels are clamped to the screen width and their grids collapse to one column below the sm breakpoint.
- For a full mobile menu, render the same links in a Drawer behind a menu button and show Navigation Menu from the md breakpoint.
Accessibility
- Rendered as a
<nav>landmark; name it witharia-labelwhen the page has more than one. - Triggers are buttons with
aria-expandedandaria-controls. Enter or Space opens a panel; ArrowDown or Tab moves into it; Escape closes it and returns focus to the trigger. - Left/Right arrows move between top-level items. Items are links, not menu items, so screen readers list them as links.
activesetsaria-current="page". External links say "(opens in a new tab)".- Hover opens panels after a short delay; pointer and keyboard both work, so nothing is hover-only.
API Reference
Import with import * as NavigationMenu from "@/components/ui/NavigationMenu".
NavigationMenu.Root
See Radix UI docs for base props.
| Prop | Type | Default | Description |
|---|---|---|---|
viewport | "boolean" | "true" | Render panels in the shared viewport. |
value / defaultValue / onValueChange | "string" | "undefined" | The open item (controlled). |
delayDuration | "number" | "200" | Hover delay before opening (ms). |
orientation | "horizontal""vertical" | "horizontal" | Arrow-key direction. |
aria-label | "string" | "undefined" | Landmark name. |
className | "string" | "undefined" | Additional classes, merged last. |
NavigationMenu.List
The top-level list.
| Prop | Type | Default | Description |
|---|---|---|---|
className | "string" | "undefined" | Additional classes, merged last. |
NavigationMenu.Item
A top-level item (a link, or a trigger with content).
| Prop | Type | Default | Description |
|---|---|---|---|
className | "string" | "undefined" | Additional classes, merged last. |
NavigationMenu.Trigger
Opens the item's panel.
| Prop | Type | Default | Description |
|---|---|---|---|
className | "string" | "undefined" | Additional classes, merged last. |
NavigationMenu.Content
The panel. Lay links out inside it.
| Prop | Type | Default | Description |
|---|---|---|---|
className | "string" | "undefined" | Additional classes, merged last. |
NavigationMenu.Link
| Prop | Type | Default | Description |
|---|---|---|---|
href | "string" | "undefined" | Destination. |
active | "boolean" | "false" | The current page (aria-current="page"). |
external / externalLabel | "boolean / string" | "false / (opens in a new tab)" | New tab, safe rel, icon and text. |
variant | "panel""top" | "panel" | Block link in a panel, or top-level bar link. |
onSelect | "(event) => void" | "undefined" | Runs before the menu closes; preventDefault keeps it open. |
asChild | "boolean" | "false" | Render your router's link (e.g. Next.js Link). |
className | "string" | "undefined" | Additional classes, merged last. |
NavigationMenu.Viewport
The shared panel container (rendered by Root).
| Prop | Type | Default | Description |
|---|---|---|---|
className | "string" | "undefined" | Additional classes, merged last. |
NavigationMenu.Indicator
Optional arrow under the open trigger.
| Prop | Type | Default | Description |
|---|---|---|---|
className | "string" | "undefined" | Additional classes, merged last. |
Used in these blocks
Block families with at least one block built on this component. Each page previews its blocks and lists the components and packages they use.