Build · New

Navigation Menu

Website navigation with dropdown panels: a few destinations each with an icon and one short line, and at most one featured card.

Preview

Mirrored is the same English content laid out right to left: it separates a mirroring bug from a translation one.

Installation

SoonInstalling from the registry opens at launch. Until then the command below is what it will be.
npx shadcn@latest add @ritla/navigation-menu

Dependencies it brings: @base-ui/react, @phosphor-icons/react

Usage

import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuLinks,
  NavigationMenuList,
  NavigationMenuPanelLink,
  NavigationMenuTrigger,
} from "@/components/ui/navigation-menu";
<NavigationMenu aria-label="Main">
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuTrigger>Products</NavigationMenuTrigger>
      <NavigationMenuContent>
        <NavigationMenuLinks>
          <NavigationMenuPanelLink href="/payments" icon={CreditCardIcon} title="Payments" description="Accept cards, Apple Pay and CliQ." />
        </NavigationMenuLinks>
      </NavigationMenuContent>
    </NavigationMenuItem>
    <NavigationMenuItem>
      <NavigationMenuLink href="/pricing">Pricing</NavigationMenuLink>
    </NavigationMenuItem>
  </NavigationMenuList>
</NavigationMenu>

Examples

One column, and the current page

columns={1} for short panels, with no featured card. The plain link for the current page takes active (aria-current="page").

API reference

NavigationMenu

PropTypeDefaultDescription
aria-labelstringThe navigation's name, when the page has more than one nav.
delay / closeDelaynumber50 / 50The wait before opening and closing on hover (ms).
value / onValueChangestring | nullThe open panel, to control it from code.

NavigationMenuTrigger

PropTypeDefaultDescription
childrenReactNodeFigma's Label. The caret is added for you.

NavigationMenuLink

PropTypeDefaultDescription
hrefstringA plain link in the row, with no panel.
activebooleanThe current page.
renderReactElementYour framework's link, e.g. Next's <Link />.

NavigationMenuLinks

PropTypeDefaultDescription
columns1 | 22Link columns, 220px each.

NavigationMenuPanelLink

PropTypeDefaultDescription
iconIconComponentAn icon in a brand/faint box.
titleReactNodeFigma's Title: the destination.
descriptionReactNodeFigma's Description: one short line.
href / renderstring / ReactElementThe link.

NavigationMenuFeatured

PropTypeDefaultDescription
tagReactNodeThe small tag at the top ("New").
title / descriptionReactNodeTitle and description.
linkLabelReactNodeThe call to action at the bottom; the whole card is the link.

Accessibility

Keyboard

Keys are written for left-to-right. In right-to-left the arrow keys swap: the one pointing toward the reading direction moves forward.

KeyAction
TabAlong the row; from an open trigger through its panel's links, then on to the next item.
EnterSpaceOn a trigger: opens or closes its panel.
ArrowRightArrowLeftAlong the row; in Arabic, ArrowLeft goes to the next.
EscCloses the panel and returns focus to its trigger.

ARIA

  • A <nav> with a list (ul) of items; each trigger has aria-expanded and aria-controls.
  • Panel links are real links, and the featured card is one link.
  • Triggers are 32px tall with a 48px hit area vertically only.
  • On phones: a menu button that opens a Drawer with the same groups in an Accordion.

Arabic and RTL notes

Mirrors

  • The first item sits on the right, and the panel starts at the row's right edge.
  • Panel links read from the right, and the featured card sits on the left.

Does not mirror

  • The trigger's caret points down and turns when open; it doesn't mirror.
  • The links' icons don't mirror.
Numerals
Numbers in descriptions follow the numerals setting (toNumerals for fixed strings).
Arabic typography
Triggers label-14 Medium, link titles label-14 Semibold, descriptions label-12, the card title label-16 Semibold.
Mixed-direction text
Latin product names (Apple Pay, iOS) inside an Arabic description keep their order. The panel carries the page's direction and language into the portal.

All components ›