Navigation Menu

Menus that open on hover and share one floating panel, so moving between triggers resizes and slides the same surface instead of opening a new popover.

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add navigation-menu

Usage#

usage.tsxTSX
import {  NavigationMenu,  NavigationMenuList,  NavigationMenuItem,  NavigationMenuTrigger,  NavigationMenuContent,  NavigationMenuLink,} from "@/components/ui/navigation-menu"export function Example() {  return (    <NavigationMenu>      <NavigationMenuList>        <NavigationMenuItem>          <NavigationMenuTrigger>Product</NavigationMenuTrigger>          <NavigationMenuContent>            <NavigationMenuLink href="/analytics">Analytics</NavigationMenuLink>          </NavigationMenuContent>        </NavigationMenuItem>      </NavigationMenuList>    </NavigationMenu>  )}

Columns#

For a wide menu, set NavigationMenuGroups side by side, each under a NavigationMenuGroupLabel, and close the panel with a NavigationMenuFooter for the link to everything else.

variant="card" turns a link into a featured block: a NavigationMenuLinkMedia picture over its title and description, beside the rows. The whole card is the link.

Category rail#

A NavigationMenuSub nests a menu inside the panel: a rail of categories down the side and a pane that switches the moment the pointer reaches the next one, with no delay. Its defaultValue picks the pane that shows first.

Icon tiles#

NavigationMenuLinkIcon sets a row's glyph in a 32px tile. A brand logo keeps its own colours there, where a bare icon in a row is muted, so it's the pick for integrations and apps.

Timing#

A trigger opens after delayDuration (200ms), so a cursor passing over the bar doesn't flash every menu. Reach a sibling trigger within skipDelayDuration (300ms) and it opens at once.

Without the shared panel#

viewport={false} gives each trigger its own panel, opened under it. Switching closes one and opens the next, so reach for it only when the menus are far apart.

Density#

density on the root sets the row height of every link in the menu. The panel padding stays put, so the corners stay concentric in both.

API reference#

NavigationMenu

The root. Forwards Radix's delayDuration, skipDelayDuration and value / onValueChange. viewport (default true) renders the shared panel; density sets the row height of every link.

NavigationMenuList / NavigationMenuItem

The row and each entry in it. An item holds a trigger and its content, or a single NavigationMenuLink variant="bar".

NavigationMenuTrigger / NavigationMenuContent

The chip in the bar and the contents of its panel. The caret turns while the panel is open.

NavigationMenuLink

variant: "row" (default), a row in a panel; "bar", a plain entry beside the triggers; or "card", a featured block. active marks the current page. Wrap a title and a NavigationMenuLinkDescription in NavigationMenuLinkText for a described row.

NavigationMenuLinkIcon / NavigationMenuLinkMedia

A 32px tile for a row's glyph, where a brand logo keeps its colours, and the inset picture frame of a card link. Put an <img> inside the frame; it owns an aspect-video ratio you can override.

NavigationMenuGroup / NavigationMenuGroupLabel / NavigationMenuFooter

A labelled column of links, its small muted heading, and the panel's foot under a hairline. Each is optional: a group reads fine without its label, and a footer with nothing above it drops its rule.

NavigationMenuSub / NavigationMenuSubViewport

A menu inside a panel. The Sub holds a NavigationMenuList rail (vertical by default) and, after it, the viewport the active pane shows in. It forwards Radix's defaultValue, value and orientation.

NavigationMenuIndicator / NavigationMenuViewport

The tip that slides under the active trigger (optional, the list's last child), and the shared panel, which the root already renders.

FAQ#

DropdownMenu opens on click and every instance is its own popover: right for a single menu, like a Navbar's Collections link. NavigationMenu opens on hover and shares one panel across every trigger, so crossing from one to the next resizes that panel instead of swapping popovers.