Navigation Menu
Top navigation with mega-menu panels and a moving light indicator.
Built on Icons. Installs @floating-ui/react-dom and motion.
Ship to every region in one push.
Functions, storage and observability on one network, 50 ms from every user.
Installation
npx shadcn@latest add https://neonkit.heyaadi.com/r/navigation-menu.jsonUsage
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from "@/components/ui/navigation-menu"
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Product</NavigationMenuTrigger>
<NavigationMenuContent className="w-96 p-2">
<NavigationMenuLink href="/edge" className="p-3">Edge Functions</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="/docs">Docs</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>Examples
Compact panels
Plain link lists, and active on the current page's link.
Links only
Without panels it's a section bar. Wire active to your router; here clicks swap it client-side.
API reference
NavigationMenu
The <nav> landmark. It also hosts the shared panel, so keep it position: relative. Accepts native nav attributes.
| Prop | Type | Default |
|---|---|---|
color | NeonColorPalette name or hex. Falls back to --neon-accent, then cyan. | inherited |
value | stringControlled open item, matched against NavigationMenuItem value. "" when closed. | None |
defaultValue | stringInitially open item when uncontrolled. | "" |
onValueChange | (value: string) => voidCalled when a panel opens, switches or closes. | None |
aria-label | stringNames the landmark. Change it when a page has more than one nav. | "Main" |
NavigationMenuList
The <ul> of top-level items, with the gliding indicator. Accepts native ul attributes.
| Prop | Type | Default |
|---|
NavigationMenuItem
An <li>. Holds either a trigger with its content, or a link.
| Prop | Type | Default |
|---|---|---|
value | stringIdentifies the item for value and onValueChange. Generated when omitted. | None |
NavigationMenuTrigger
A button with a chevron that opens the item's panel. Accepts native button attributes.
| Prop | Type | Default |
|---|
NavigationMenuContent
The item's panel content. It renders inside the shared panel, not in place, and accepts native div attributes. Give it a width such as w-[min(600px,calc(100vw-48px))].
| Prop | Type | Default |
|---|
NavigationMenuLink
A link. At the top level it's styled like a trigger; inside a panel it's a bare block for your own layout. Clicking it closes the panel.
| Prop | Type | Default |
|---|---|---|
active | booleanMarks the current page with aria-current="page" and a softly lit label. | false |
asChild | booleanRenders the single child, e.g. your router's Link, with the link's behaviour and styles. | false |
Accessibility
- Opens on hover after a 150ms intent delay, then switches between menus instantly. Clicking toggles; clicking a menu that just opened on hover keeps it open.
- Enter, Space and ArrowDown open a panel and move focus into it. ArrowUp and ArrowDown move inside the panel, Shift+Tab from its first link returns to the trigger, and Tab from its last link continues along the bar.
- ArrowLeft and ArrowRight move between top-level items, and swap panels while one is open. Escape closes and returns focus to the trigger.
- Triggers carry aria-expanded and aria-controls; each panel is labelled by its trigger.
- Below the sm breakpoint the bar scrolls sideways and panels cap their width to the screen. For a full mobile menu, swap it for a Sheet.