Navigation menu
Site navigation with dropdowns, or one full-width panel that stays open while its content slides between menus.
pnpm dlx shadcn@latest add https://hextaui.com/r/navigation-menu.jsonAdds the component, the HextaUI theme tokens and any HextaUI components it depends on.
Add the theme tokens to your global CSS, if you haven’t yet.
Install the dependencies.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnCopy and paste the following code into your project.
components/ui/navigation-menu.tsx lib/motion.ts Update the import paths to match your project setup.
With variant="panel", one card spans the whole bar. Moving between triggers keeps it open and in place: only the content slides toward the direction you moved, and the height eases to fit. Nothing closes, reopens or jumps.
The default dropdown variant opens a card under each trigger. Moving to the next trigger glides the same card over and resizes it to the new content.
Links in the bar look like triggers. Mark the current page with active, which also sets aria-current="page".
Content slides follow the direction you move, which flips in right-to-left layouts.
| Key | Action |
|---|---|
| Tab | Moves through the bar, and from an open trigger into its content. |
| EnterSpace | Opens or closes the focused trigger's menu. |
| ↑↓ | Moves between links in the open content. |
| ←→ | Moves between triggers in the bar. |
| Esc | Closes the menu and returns focus to its trigger. |
- The root renders a
<nav>. Give it anaria-labelwhen the page has more than one. - Triggers are buttons that report whether their menu is open, and focus returns to them when the menu closes.
- The content slide and the sliding highlight turn into fades when reduced motion is on.
| Prop | Type | Default |
|---|---|---|
variantdropdown opens under each trigger. panel opens one full-width card under the bar that stays put while content slides. | "dropdown" | "panel" | "dropdown" |
showSafeAreaDraws the safe area that keeps a menu open while the pointer heads into it. For debugging and demos. | boolean | false |
align | "start" | "center" | "end" | "start", or "center" for panel |
sideOffset | number | 8 |
value | any | – |
defaultValue | any | – |
onValueChange | (value, details) => void | – |
delayWait before opening on hover, in ms. | number | 50 |
closeDelayWait before closing after the pointer leaves, in ms. | number | 50 |
orientation | "horizontal" | "vertical" | "horizontal" |
| Attribute | Description |
|---|---|
data-slot="navigation-menu" | The nav, with data-variant. |
data-slot="navigation-menu-highlight" | The background that slides between open triggers. |
data-slot="navigation-menu-popup" | The card. Its height eases through --popup-height. |
| Attribute | Description |
|---|---|
data-slot="navigation-menu-trigger" | Target triggers in CSS. |
data-popup-open | Present while its menu is open. The chevron flips. |
| Attribute | Description |
|---|---|
data-slot="navigation-menu-content" | A menu's content, with data-variant. |
data-activation-direction | "left", "right", "up" or "down": where the previous trigger was. Drives the slide. |
--navigation-menu-link-radius | Link corner radius, concentric with the card. |
| Prop | Type | Default |
|---|---|---|
activeMarks the current page. | boolean | false |
render | ReactElement | (props, state) => ReactElement | <a> |
| Attribute | Description |
|---|---|
data-slot="navigation-menu-link" | Target links in CSS. In the bar they size themselves like triggers. |
data-active | Present on the current page. |
- MotionThe easing curves, durations and reduced-motion check every component animates with, plus hooks for size morphs and sliding highlights.
- BreadcrumbA trail of links to the current page that wraps safely, mirrors in right-to-left layouts and expands collapsed segments in place.
- PaginationPage navigation that keeps every button in place, glides to the current page and jumps to any page from the ellipsis.
- SidebarAn app sidebar that collapses to icons or off canvas, stays pinned under your header, and becomes a swipeable sheet on phones.
- TabsSwitch between views with an indicator that slides to the active tab, as a segmented control or an underline, and lists that scroll when they overflow.