Skip to content

NavigationMenu

A site's navigation: a row of destinations, some of which open a panel of more of them. Every row is a real link, which is what puts it in the link list, on the status bar and in a crawler's index.

tsx
import { NavigationMenu, NavigationMenuItem, NavigationMenuLink } from 'neba';

<NavigationMenu aria-label="Main">
  <NavigationMenuItem label="Product">
    <NavigationMenuLink href="/analytics" title="Analytics" description="Every number." />
  </NavigationMenuItem>
  <NavigationMenuItem label="Pricing" href="/pricing" />
</NavigationMenu>;

Props

PropTypeDefaultDescription
sizeshared'xs' | 'sm' | 'md' | 'lg' | 'xl''md'The height and type scale of the items, and of the links in the panels
colorshared'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'The role the open item and the panel edge carry
densityshared'default' | 'compact''default'Horizontal padding only
orientationshared'horizontal' | 'vertical''horizontal'Which way the row runs. Vertical is a nav rail whose panels open beside it
valuestring | nullWhich item's panel is open, by its value. Nullish means closed
defaultValuestring | nullWhich starts open, uncontrolled
onValueChange(value: string | null) => voidFired whenever the open item changes
delaynumber50How long the pointer rests before a panel opens, in milliseconds
closeDelaynumber50How long a panel stays after the pointer leaves, in milliseconds
sideOffsetnumber8Distance from the row, in pixels
childrenReactNodeThe items

Every native <nav> attribute passes through, apart from color.

The difference from a Menu is what the rows are. A menu holds actions, so its rows are menuitems. This holds links, so it is a <nav> full of <a>s. Reach for a Menu when the row does something and for this when the row goes somewhere.

PropTypeDefaultDescription
label * ReactNodeThe word in the row
hrefstringMakes the item a plain link rather than something that opens a panel. An item with an href and no children is a destination, and it is announced as one
targetstringWhere the link opens. Ignored without href. Anything other than this tab also gets noopener noreferrer added to rel
relstringThe link's rel. Merged rather than replaced, so writing nofollow does not take the protection off a link that still opens elsewhere
startIconReactNodeContent before the label
valuestringIdentifies the item, for a controlled menu
disabledbooleanfalseUnavailable. The word stays in the row and opens nothing
columnsnumber1How many columns the panel lays its links out in
childrenReactNodeThe panel's contents: usually NavigationMenuLinks
PropTypeDefaultDescription
href * stringWhere it goes
title * ReactNodeThe row's name
descriptionReactNodeA second line under it, one step down the scale and muted
startIconReactNodeA glyph before the title

Examples

Items with and without a panel

An item with children is a trigger and a panel; an item with an href and nothing else is a link, and the two are announced differently.

columns

How many columns the panel lays its links out in. One is right for a short list; a wide menu of regions or products wants two or three.

orientation

vertical stacks the items and opens the panels beside them: a nav rail rather than a bar.

In a header

Accessibility

  • Renders a real <nav>; give it an aria-label where a page holds more than one.
  • Every destination is an <a href>, so it can be opened in a new tab, copied, followed by a crawler and reached from a screen reader's link list.
  • The row is keyboard-driven: the arrow keys move between items and into an open panel, and Escape closes it.
  • A panel resizes between items rather than closing and reopening, so crossing the row reads as one surface.

Released under the MIT License