@biem/ui

Navigation Menu

A row of triggers and links that leads users to the sections of an application.

A navigation menu lists the sections of an application in a row. A trigger opens the links of its section in a popup when users rest the mouse pointer on it or press it, and a link in the row leads to its page directly. All triggers share one popup, which NavigationMenu renders itself. The popup moves to the active trigger and takes the size of its content, so the examples set a width on the list of links. Users move through the row with the left and right arrow keys and open the popup of a trigger with the down arrow key. The popup closes when users press Escape, press outside of it or move the focus out of the navigation menu. A popup that opened under the resting pointer also closes when the pointer leaves the trigger and the popup.

Usage

navigation-menu-default.tsx
import {
	NavigationMenu,
	NavigationMenuContent,
	NavigationMenuItem,
	NavigationMenuLink,
	NavigationMenuList,
	NavigationMenuTrigger,
} from "@biem/ui/components/ui/navigation-menu";

export function NavigationMenuDefault() {
	return (
		<NavigationMenu>
			<NavigationMenuList>
				<NavigationMenuItem>
					<NavigationMenuTrigger>Inventory</NavigationMenuTrigger>
					<NavigationMenuContent>
						<ul className="w-48">
							<li>
								<NavigationMenuLink href="/inventory/transfers">Transfers</NavigationMenuLink>
							</li>
							<li>
								<NavigationMenuLink href="/inventory/deliveries">Deliveries</NavigationMenuLink>
							</li>
							<li>
								<NavigationMenuLink href="/inventory/stock-counts">Stock counts</NavigationMenuLink>
							</li>
						</ul>
					</NavigationMenuContent>
				</NavigationMenuItem>
				<NavigationMenuItem>
					<NavigationMenuTrigger>Orders</NavigationMenuTrigger>
					<NavigationMenuContent>
						<ul className="w-48">
							<li>
								<NavigationMenuLink href="/orders/purchase-orders">Purchase orders</NavigationMenuLink>
							</li>
							<li>
								<NavigationMenuLink href="/orders/returns">Returns</NavigationMenuLink>
							</li>
						</ul>
					</NavigationMenuContent>
				</NavigationMenuItem>
			</NavigationMenuList>
		</NavigationMenu>
	);
}

Examples

Some sections consist of a single page, such as the daily overview of a store, and a popup with one entry would only add a step. Placed directly in an item, without a trigger, a link takes users to that page with a single click.

With Icon

Users who return to the same pages every day learn to find them by shape before they read a word. An icon inside a link supports that recognition, while the name of the page keeps the meaning clear for users who see the icon for the first time.

Orientation matters most deep inside an application, where many pages resemble each other. Marked with active, a link shows the page that users are on, visibly and for assistive technology, so they recognize their position as soon as they open its section.

Close on Click

Applications that switch pages without a full reload keep the navigation menu in place, so a popup that stays open would cover part of the page that users just opened. With closeOnClick on a link, the popup closes as soon as users choose that link, and the new page appears unobstructed.

Disabled Trigger

Now and then a section is unavailable, for example because users lack the rights for it. Set on its trigger, disabled keeps the popup of that section closed, yet the trigger stays focusable, so users who move through the navigation with the keyboard still learn that the section exists.

Open by Default

A start page often exists to send users onward to their daily work. Through defaultValue, the popup of one section is already open at first render, and from then on users move to another section or close the popup as usual.

Controlled

Sometimes the application decides which section is open, for example when a notice on the page guides users to the section where their next task waits. With value and onValueChange, the application holds the open item itself, so any part of the interface can open a section or close the popup.

API Reference

Propvalue
Typeany
Default–
DescriptionSets the value of the item whose popup is open and makes the navigation menu controlled. With null, the popup is closed. Update it in onValueChange.
PropdefaultValue
Typeany
Defaultnull
DescriptionSets the value of the item whose popup is open at first render. The navigation menu then tracks the open item itself.
ProponValueChange
Type(value: any, eventDetails: NavigationMenuRootChangeEventDetails) => void
Default–
DescriptionRuns when users open the popup of an item, move to another item or close the popup. It receives the value of the item that is open afterwards, or null when the popup closes.
ProponOpenChangeComplete
Type(open: boolean) => void
Default–
DescriptionRuns after the popup has closed and its animations have finished. It receives false.
PropactionsRef
TypeRefObject<NavigationMenuRootActions | null>
Default–
DescriptionReceives the function unmount, which removes the closed popup from the DOM. With actionsRef, the navigation menu no longer removes the popup itself, so code that controls the closing animation calls unmount when the animation has finished.
Propdelay
Typenumber
Default50
DescriptionSets how many milliseconds the pointer must rest on a trigger before the popup opens. While the popup is open, the pointer moves it to another trigger without this delay.
PropcloseDelay
Typenumber
Default50
DescriptionSets how many milliseconds the popup stays open after the pointer has left the trigger and the popup.
Proporientation
Type"horizontal" | "vertical"
Default"horizontal"
DescriptionSets the arrow keys that move through the triggers and links of the list: left and right for "horizontal", up and down for "vertical". The key that opens a popup follows it: the down arrow for "horizontal", and for "vertical" the right arrow, or the left arrow in a right-to-left layout. It doesn't change the layout of the items.
Propalign
Type"start" | "center" | "end"
Default"start"
DescriptionSets where the popup lines up with the active trigger: at its start, its center or its end. NavigationMenu passes it to the NavigationMenuPositioner that it renders after its children.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the navigation menu with another component.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the list with another component.
Propvalue
Typeany
Default–
DescriptionIdentifies the item in value and defaultValue of the navigation menu. Without it, the item gets a generated ID.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the item with another component.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the trigger with another component.
PropnativeButton
Typeboolean
Defaulttrue
DescriptionDeclares whether the rendered element is a native button. Set it to false when render returns a different element.
Propdisabled
Typeboolean
Defaultfalse
DescriptionPrevents users from opening the popup of the item with this trigger. The trigger stays focusable.
PropkeepMounted
Typeboolean
Defaultfalse
DescriptionKeeps the content in the DOM while the popup of its item is closed. The page that the server renders then contains the content, so web crawlers find its links.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the content with another component.
Prophref
Typestring
Default–
DescriptionSets the address of the page that the link opens. Leave it out when render supplies an element that carries its own address.
Propactive
Typeboolean
Defaultfalse
DescriptionMarks the link as the page that users are on. It highlights the link and reports the current page to assistive technology.
PropcloseOnClick
Typeboolean
Defaultfalse
DescriptionCloses the popup when users click the link. Without it, a click leaves the popup open.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the link with another component.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the indicator with another component.
Propside
Type"top" | "bottom" | "left" | "right" | "inline-end" | "inline-start"
Default"bottom"
DescriptionSets the side of the active trigger that the popup opens on. "inline-start" and "inline-end" follow the reading direction. The popup moves to the opposite side when the chosen one has too little space.
PropsideOffset
Typenumber | OffsetFunction
Default8
DescriptionSets the distance between the active trigger and the popup in pixels. A function receives the side, the alignment and the dimensions of the trigger and the positioner, and returns the distance.
Propalign
Type"start" | "center" | "end"
Default"start"
DescriptionSets where the popup lines up with the active trigger along the chosen side: at its start, its center or its end.
PropalignOffset
Typenumber | OffsetFunction
Default0
DescriptionMoves the popup along the alignment axis by a number of pixels. A function receives the same data as the one for sideOffset and returns the offset.
Propanchor
TypeElement | VirtualElement | RefObject<Element | null> | (() => Element | VirtualElement | null) | null
Default–
DescriptionSets the element that the popup is positioned against. Without it, the popup uses the active trigger.
ProppositionMethod
Type"absolute" | "fixed"
Default"absolute"
DescriptionSets the CSS position that places the popup.
PropcollisionBoundary
Type"clipping-ancestors" | Element | Element[] | Rect
Default"clipping-ancestors"
DescriptionSets the area that the popup must stay in: the ancestors that clip it, one or several elements, or a rectangle.
PropcollisionPadding
Typenumber | { top?: number; right?: number; bottom?: number; left?: number }
Default5
DescriptionSets the distance in pixels that the popup keeps from the edge of the collision boundary.
PropcollisionAvoidance
TypeCollisionAvoidance
Default{ fallbackAxisSide: "none" }
DescriptionSets how the popup reacts when it doesn't fit in the collision boundary. side takes "flip" to move the popup to the opposite side, or "shift" to keep the side and push the popup back into the boundary. align takes "flip" to swap start and end, or "shift" to push the popup along its side. fallbackAxisSide takes "start" or "end" to let the popup move to a side on the other axis. Each of them takes "none" to switch its reaction off. A navigation menu inside another one uses "end" for fallbackAxisSide by default.
Propsticky
Typeboolean
Defaultfalse
DescriptionKeeps the popup in the viewport after its trigger has been scrolled out of view.
ProparrowPadding
Typenumber
Default5
DescriptionSets the minimum distance between an arrow and the edges of the popup. The positioner renders no arrow, so it has no effect.
PropdisableAnchorTracking
Typeboolean
Defaultfalse
DescriptionStops the popup from following its trigger when the layout shifts.
Proprender
TypeReactElement | render function
Default–
DescriptionReplaces the native element or composes the positioner with another component.