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.