Skip to content
Component installs need the registry setup— the Base UI shadcn project, the @vegastack namespace and the Cloudflare Access service token.
VegaStack Design

Navigation Menu

Site-nav mega-dropdown — chip triggers, one shared sliding panel, grid links with color-carried hierarchy.

Status
stable
Since
0.3.0
Accessibility pattern
APG disclosure navigation

Last updated

Install

Add Navigation Menu from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.

pnpm dlx shadcn@latest add @vegastack/navigation-menu

The same command installs the registry items it composes: @vegastack/floating-surface.

Usage

import {
  NavigationMenu,
  NavigationMenuList,
  NavigationMenuItem,
  NavigationMenuTrigger,
  NavigationMenuContent,
  NavigationMenuLink,
  NavigationMenuGridLink,
  NavigationMenuPanel,
} from "@/components/ui/navigation-menu";

Compose triggers + contents inside the list, then render NavigationMenuPanel ONCE after it — every item's content slides inside that single shared popup (Base UI viewport model).

Anatomy

  • Triggers follow the ghost-chip grammar and stay lit while open (data-popup-open).
  • NavigationMenuGridLink carries hierarchy by color at one size — title ink, description muted — per the menu-typography rule.
  • The panel is the standard overlay surface: popover fill, one hairline, --shadow-overlay, scale-0.97 + 1px nudge enter.
  • Keyboard/hover open behavior, focus management, and dismissal come from the Base UI primitive.
NavigationMenu — data-slot="navigation-menu"
NavigationMenuContent — data-slot="navigation-menu-content"
NavigationMenuGridLink — data-slot="navigation-menu-grid-link"
NavigationMenuItem — data-slot="navigation-menu-item"
NavigationMenuLink — data-slot="navigation-menu-link"
NavigationMenuList — data-slot="navigation-menu-list"
NavigationMenuPanel
NavigationMenuTrigger — data-slot="navigation-menu-trigger"

Examples

The example composes two disclosure triggers and one direct link. Both disclosure contents render through the single shared NavigationMenuPanel.

Narrow viewports

Constrained to a phone-width column, the trigger row wraps and each panel becomes a single stacked list rather than a multi-column grid — nothing is hidden behind a breakpoint, and the popup still sizes itself to its content:

API Reference

Root and list

NavigationMenu adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Data attributes and CSS variables on NavigationMenu

AttributeValues
data-slot"navigation-menu"

NavigationMenuList adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Data attributes and CSS variables on NavigationMenuList

AttributeValues
data-slot"navigation-menu-list"

NavigationMenuItem adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Data attributes and CSS variables on NavigationMenuItem

AttributeValues
data-slot"navigation-menu-item"

NavigationMenuTrigger adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Data attributes and CSS variables on NavigationMenuTrigger

AttributeValues
data-slot"navigation-menu-trigger"

NavigationMenuLink adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Data attributes and CSS variables on NavigationMenuLink

AttributeValues
data-slot"navigation-menu-link"
PropTypeDefaultDescription
title*React.ReactNodeThe entry name — ink voice.
descriptionReact.ReactNodeMuted one-line description under the title.
iconReact.ReactNodeLeading icon (decorative).

Data attributes and CSS variables on NavigationMenuGridLink

AttributeValues
data-slot"navigation-menu-grid-link"

Content and shared panel

NavigationMenuContent adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Data attributes and CSS variables on NavigationMenuContent

AttributeValues
data-slot"navigation-menu-content"

NavigationMenuPanel adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Accessibility

  • Give the root a unique navigation label when more than one navigation landmark exists.
  • Base UI owns roving focus, trigger expansion state, dismissal, and focus restoration.
  • Grid-link icons are decorative; the visible title remains each link's accessible name.
  • The shared portaled panel preserves a surrounding MarketingSurface theme scope.
KeyAction
TabEnter the navigation list and move to the next page control.
/ Move between top-level items; direction mirrors in RTL.
Enter / SpaceOpen the focused trigger or follow a direct link.
EscClose the panel and return focus to its trigger.
ContractStates tested
Behaviourdefault, open
Accessibilitynative-or-base-ui-semantics, browser-accessibility-test
Visualdefault, hover

Do / Don't

Do
Render one shared NavigationMenuPanel after the list and keep link titles short, specific, and sentence case.
Don't
Mount a separate popup per item or hide essential destinations behind hover-only interaction.

On this page