Navigation Menu
A dependency-free navigation menu with trigger-owned panels, link triggers, viewport sizing, indicator hooks, and keyboard navigation.
import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger } from 'radcn/navigation-menu'Live package example
Render the upstream docs-style navigation menu with exact panel copy, responsive sections, icon links, and viewport behavior.
Navigation Menu Demo
Render the upstream docs-style navigation menu with exact panel copy, responsive sections, icon links, and viewport behavior.
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuIndicator,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
NavigationMenuViewport,
} from 'radcn/navigation-menu'
const components = [
{
title: 'Alert Dialog',
href: '/docs/primitives/alert-dialog',
description:
'A modal dialog that interrupts the user with important content and expects a response.',
},
{
title: 'Hover Card',
href: '/docs/primitives/hover-card',
description: 'For sighted users to preview content available behind a link.',
},
{
title: 'Progress',
href: '/docs/primitives/progress',
description:
'Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.',
},
{
title: 'Scroll-area',
href: '/docs/primitives/scroll-area',
description: 'Visually or semantically separates content.',
},
{
title: 'Tabs',
href: '/docs/primitives/tabs',
description:
'A set of layered sections of content—known as tab panels—that are displayed one at a time.',
},
{
title: 'Tooltip',
href: '/docs/primitives/tooltip',
description:
'A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.',
},
]
export function NavigationMenuDemo() {
return (
<NavigationMenu defaultValue="home" id="navigation-menu-demo">
<NavigationMenuList class="flex-wrap">
<NavigationMenuItem value="home">
<NavigationMenuTrigger>Home</NavigationMenuTrigger>
<NavigationMenuContent>
<div class="navigation-menu-home-grid">
<NavigationMenuLink href="/">
<div>shadcn/ui</div>
<p>Beautifully designed components built with Tailwind CSS.</p>
</NavigationMenuLink>
<div>
<ListItem href="/docs" title="Introduction">
Re-usable components built using Radix UI and Tailwind CSS.
</ListItem>
<ListItem href="/docs/installation" title="Installation">
How to install dependencies and structure your app.
</ListItem>
<ListItem href="/docs/primitives/typography" title="Typography">
Styles for headings, paragraphs, lists...etc
</ListItem>
</div>
</div>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem value="components">
<NavigationMenuTrigger>Components</NavigationMenuTrigger>
<NavigationMenuContent>
<div class="navigation-menu-components-grid">
{components.map((component) => (
<ListItem href={component.href} title={component.title}>
{component.description}
</ListItem>
))}
</div>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem value="docs">
<NavigationMenuLink href="/docs">Docs</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem class="desktop-only" value="list">
<NavigationMenuTrigger>List</NavigationMenuTrigger>
<NavigationMenuContent>
<ListItem href="#" title="Components">Browse all components in the library.</ListItem>
<ListItem href="#" title="Documentation">Learn how to use the library.</ListItem>
<ListItem href="#" title="Blog">Read our latest blog posts.</ListItem>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem class="desktop-only" value="simple">
<NavigationMenuTrigger>Simple</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuLink href="#">Components</NavigationMenuLink>
<NavigationMenuLink href="#">Documentation</NavigationMenuLink>
<NavigationMenuLink href="#">Blocks</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem class="desktop-only" value="with-icon">
<NavigationMenuTrigger>With Icon</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuLink href="#">? Backlog</NavigationMenuLink>
<NavigationMenuLink href="#">o To Do</NavigationMenuLink>
<NavigationMenuLink href="#">✓ Done</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
<NavigationMenuIndicator />
<NavigationMenuViewport />
</NavigationMenu>
)
}
function ListItem({ children, href, title }) {
return (
<NavigationMenuLink href={href}>
<div>{title}</div>
<p>{children}</p>
</NavigationMenuLink>
)
}Installation
Intended future install command. RadCN is private and not published to npm yet, so this snippet documents the target user-facing API rather than something external consumers can run today.
pnpm add radcn # intended future package
import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger } from 'radcn/navigation-menu'Theming
RadCN tokens read the resolved theme from the document. Store the user's preference separately, then resolve system preferences to a concrete light or dark theme before setting package tokens.
<html data-radcn-theme-mode="system" data-radcn-theme="dark">
...
</html>Accessibility
- NavigationMenu renders a labelled nav landmark and native list structure for top-level controls.
- Triggers receive aria-controls and aria-expanded during enhanceNavigationMenu, while content panels stay associated with their owning item.
- Links remain native anchors, so the Docs trigger-style link keeps normal link behavior.
- Keyboard movement covers horizontal roving focus, Home, End, Enter or Space opening, Escape close, and focusout close without React state.
Customization
- Root, list, item, trigger, content, link, viewport, and indicator parts expose public data-radcn-navigation-menu hooks and package classes.
- The Docs link uses the public NavigationMenuLink class as the RadCN equivalent of upstream navigationMenuTriggerStyle().
- The upstream viewport={isMobile} recipe maps to explicit NavigationMenuViewport composition plus documented app-owned responsive behavior.
- Responsive desktop-only sections use app-owned CSS over public item classes, preserving the upstream hidden md:block behavior without Tailwind.
- Icon links are app-owned presentation over NavigationMenuLink; apps may use text glyphs, inline SVG, or an icon package without changing RadCN.
Remix 3 Notes
- use client, React state, Next Link, useIsMobile, Radix Navigation Menu, and cva map to server-rendered RadCN markup plus scoped enhanceNavigationMenu browser behavior.
- lucide ChevronDownIcon, CircleHelpIcon, CircleIcon, and CircleCheckIcon remain app presentation and are not RadCN dependencies.
- className maps to class, cn maps to explicit class composition, and data-slot maps to public data-radcn-navigation-menu* hooks.
- Tailwind grid, width, gap, flex-wrap, rounded, muted, transition, hidden md:block, and text utilities map to package CSS, docs-owned styles, CSS variables, and media queries.
- NavigationMenuIndicator is package capability evidence; the upstream demo relies on root-rendered viewport behavior rather than explicitly rendering an indicator.
- Vendor source remains read-only evidence and is not imported by RadCN.
