Skip to Content
⭐️ Leave a star →
ComponentsNavigationMenu

Navigation Menu

Top navigation with hover-driven dropdown panels. Supports plain links (no dropdown) and mega-menu style panels. Configurable hover delays for both open and close.

Features

Hover-to-open with configurable delay.
Skip-delay window for moving from trigger to content.
Switching between open menus is instant (no second delay).
Mix plain links and dropdown triggers in the same bar.
Active-link styling via data-active.
Renders as a real <nav> element with aria-label.

Example

import { NavigationMenu } from '@wire-ui/react' <NavigationMenu.Root> <NavigationMenu.List> <NavigationMenu.Item> <NavigationMenu.Link href="/" active>Home</NavigationMenu.Link> </NavigationMenu.Item> <NavigationMenu.Item value="products"> <NavigationMenu.Trigger>Products</NavigationMenu.Trigger> <NavigationMenu.Content> <NavigationMenu.Link href="/design">Design</NavigationMenu.Link> <NavigationMenu.Link href="/develop">Develop</NavigationMenu.Link> </NavigationMenu.Content> </NavigationMenu.Item> <NavigationMenu.Item> <NavigationMenu.Link href="/pricing">Pricing</NavigationMenu.Link> </NavigationMenu.Item> </NavigationMenu.List> </NavigationMenu.Root>

Styling

Trigger and Content expose data-state for open/closed styling. Link exposes data-active when its active prop is true.

<NavigationMenu.Trigger className="data-[state=open]:bg-[#f5f5f5]"> Products </NavigationMenu.Trigger> <NavigationMenu.Link active className="data-[active]:bg-black data-[active]:text-white"> Home </NavigationMenu.Link>

Using data attributes

[data-state="open"] { background: #f5f5f5; } [data-state="closed"] { /* default */ } [data-active] { background: #000; color: #fff; }

Root props

PropTypeDefaultDescription
valuestring | nullControlled open item value
defaultValuestring | nullnullInitial open item (uncontrolled)
onValueChange(value: string | null) => voidCalled when the open item changes
delayDurationnumber100Hover-to-open delay in ms
skipDelayDurationnumber300Time (ms) to move from trigger → content before closing
aria-labelstring'Main'Label for the rendered <nav>

Item props

PropTypeDescription
valuestringUnique id — required only when the item has a Trigger/Content pair

Trigger props

PropTypeDefaultDescription
disabledbooleanfalseDisables this trigger
PropTypeDefaultDescription
activebooleanfalseMarks the link as active; adds data-active and aria-current="page"

Data attributes

AttributeElementValues
data-stateTrigger, Content"open" / "closed"
data-activeLinkPresent when active is true
data-disabledTriggerPresent when disabled
data-hover / data-active / data-focus-visibleTriggerStandard interactive states

Root renders as <nav> with aria-label. Trigger sets aria-haspopup="menu" and aria-expanded. Content sets role="menu". Link sets aria-current="page" when active.

Accessibility

  • Open delay (delayDuration) prevents flickering when sweeping across the bar.
  • Close delay (skipDelayDuration) gives the user time to move from trigger to content.
  • When one menu is open, hovering a different trigger switches immediately (no second open delay).
  • Outside click or Escape closes the open menu.

Keyboard Interactions

KeyDescription
EnterActivates the focused trigger or link.
SpaceActivates the focused trigger.
TabMoves focus to the next trigger or link.
EscapeCloses the open menu.

Internals

Since 0.3.0, the hover-intent open/close timers are delegated to useTimeout. No public API change — the delayDuration / skipDelayDuration props behave identically.

Last updated on

MIT License © 2026 wire-ui

Navigation Menu – Wire UI