Navigation Menu

Top-level nav with menus.

Usage

Compose Root > List > Item > (Trigger + Content) or a bare Link. Root renders a <nav> landmark, so give it an aria-label.

Navigation Menu vs Menubar

This is the one to use for site navigation. Its triggers open on hover after delayDuration and on click or Enter, so the menu works for pointer, keyboard and touch alike.

Menubar is a desktop-application pattern: it assumes hover and a screen wide enough for several always-visible triggers. Neither holds on a phone. Reach for a menubar when you are building application chrome — an editor, an IDE-like tool — and for this when you are building a website's header.

Marking the current page

Set active on the Link for the page the user is on. Bits then reports aria-current="page", which is the difference between "this looks highlighted" and "this is announced as where you are". Styling it without that tells sighted users and nobody else.

Links stay real anchors throughout, so middle-click and open-in-new-tab keep working.

The optional Viewport

Add a Viewport after the List and every Content panel renders inside one shared container — so switching menus resizes a single surface instead of swapping two boxes. Bits publishes the measured size as --bits-navigation-menu-viewport-width and -height, which is what the transition animates.

Omit it and each panel positions itself against its own trigger. Both are valid; the Viewport just looks calmer when panels differ in size.

Props

NavigationMenu.Root

PropTypeDefault
value Which menu is open, by its Item value. Bindable.string''
class Extra classes merged onto the root.string—
child bits-ui Snippet<[{ props: Record<string, unknown>; }]> | undefined—
children bits-ui Snippet<[]> | undefined—
delayDuration bits-ui The amount of time in ms from when the mouse enters a trigger until the content opens.number | undefined200
dir bits-ui The reading direction of the content.Direction | undefined"ltr"
id bits-ui string | undefined—
onValueChange bits-ui The callback to call when a menu item is selected.OnChangeFn<string> | undefined—
orientation bits-ui The orientation of the menu.Orientation | undefined—
ref bits-ui HTMLElement | null | undefined—
skipDelayDuration bits-ui The amount of time in ms that a user has to enter another trigger without incurring a delay again.number | undefined300

NavigationMenu.List

PropTypeDefault
class Extra classes merged onto the list.string—
child bits-ui Snippet<[{ wrapperProps: Record<string, unknown>; } & { props: Record<string, unknown>; }] | …—
children bits-ui Snippet<[]> | undefined—
id bits-ui string | undefined—
ref bits-ui HTMLElement | null | undefined—

NavigationMenu.Trigger

PropTypeDefault
class Extra classes merged onto the trigger.string—
child bits-ui Snippet<[{ props: Record<string, unknown>; }]> | undefined—
children bits-ui Snippet<[]> | undefined—
disabled bits-ui Whether the trigger is disabled.boolean | null | undefinedfalse
id bits-ui string | undefined—
ref bits-ui HTMLElement | null | undefined—

NavigationMenu.Link

PropTypeDefault
class Extra classes merged onto the link.string—
active bits-ui Whether the link is the current active pageboolean | undefined—
child bits-ui Snippet<[{ props: Record<string, unknown>; }]> | undefined—
children bits-ui Snippet<[]> | undefined—
href html string | null | undefined—
id bits-ui string | undefined—
onSelect bits-ui A callback fired when the link is clicked. Default behavior can be prevented with `event.preventDefault()`((e: Event) => void) | undefined—
ref bits-ui HTMLElement | null | undefined—

NavigationMenu.Link

List, Trigger, Content and Viewport take class plus their native attributes. Item, Sub and Indicator are re-exported from Bits unchanged.