A composable top navigation bar with hide-on-scroll, responsive mobile menu, and client-side routing support.
Import the Navbar component and access all parts using dot notation.
import {Navbar} from "@heroui-pro/react";
<Navbar>
<Navbar.Header>
<Navbar.Brand />
<Navbar.MenuToggle />
<Navbar.Menu>
<Navbar.MenuItem />
</Navbar.Menu>
</Navbar.Header>
<Navbar.Content>
<Navbar.Item />
<Navbar.Label />
<Navbar.Separator />
<Navbar.Spacer />
</Navbar.Content>
</Navbar>A docs-site style navbar with a search bar, theme segment, and responsive mobile menu.
SaaS-style navbar with a team switcher, user dropdown, and mobile menu.
Breadcrumb-style dashboard navbar built with InlineSelect for the workspace, project, and timezone selectors.
A dense navbar tuned via --spacing and height overrides for a Luma-style compact layout.
Responsive navbar with a mobile hamburger toggle and animated dropdown menu.
Pass hideOnScroll to hide the navbar when the user scrolls down and reveal it on scroll up.
Navbar.MenuToggle and Navbar.Menu provide a built-in mobile dropdown. Use hidden md:flex on desktop-only groups and keep the toggle visible below the breakpoint:
<Navbar>
<Navbar.Header>
<Navbar.MenuToggle className="md:hidden" />
<Navbar.Brand>…</Navbar.Brand>
{/* Desktop-only nav */}
<Navbar.Content className="hidden md:flex">
<Navbar.Item href="/features">Features</Navbar.Item>
<Navbar.Item href="/pricing">Pricing</Navbar.Item>
</Navbar.Content>
</Navbar.Header>
{/* Mobile-only menu — animates in when the toggle is pressed */}
<Navbar.Menu>
<Navbar.MenuItem href="/features">Features</Navbar.MenuItem>
<Navbar.MenuItem href="/pricing">Pricing</Navbar.MenuItem>
</Navbar.Menu>
</Navbar>The menu open state can be controlled via isMenuOpen / onMenuOpenChange on Navbar, or uncontrolled via defaultMenuOpen. By default the navbar locks body scroll while the menu is open — pass shouldBlockScroll={false} to disable.
Scale the entire navbar (paddings, gaps, icon sizes) by overriding the Tailwind v4 --spacing variable on the navbar or a wrapper, and tune the bar height with the height prop:
<Navbar
height="2.75rem"
size="sm"
style={{"--spacing": "0.22rem"} as React.CSSProperties}
>
…
</Navbar>--spacing scales every Tailwind spacing utility (gap-*, p-*, size-*) inside the navbarheight overrides the internal --navbar-height CSS variablesize="sm" applies the built-in compact text + padding variantsNavbar.Item renders a real <a> element when href is set (and Navbar.MenuItem does the same for the mobile menu), so it works with any router. You have three ways to integrate client-side routing:
RouterProvider (recommended)Wrap your app once in React Aria's RouterProvider with your router's navigation function. Every Navbar.Item / Navbar.MenuItem with an href — along with any other HeroUI Pro component that links (e.g. Sidebar.MenuItem) — automatically routes through it, no per-Navbar navigate prop required. Modifier clicks (⌘/Ctrl-click) still open in a new tab, and external links keep their native behavior.
import { RouterProvider } from "react-aria-components";
import { Outlet, useHref, useNavigate } from "react-router";
export default function App() {
const navigate = useNavigate();
return (
<RouterProvider navigate={navigate} useHref={useHref}>
<main className="bg-background text-foreground min-h-dvh">
<Outlet />
</main>
</RouterProvider>
);
}With the provider in place, the Navbar needs no routing props at all:
import { Navbar } from "@heroui-pro/react";
export function AppNavbar() {
return (
<Navbar>
<Navbar.Header>
<Navbar.Brand>Acme</Navbar.Brand>
<Navbar.Content>
<Navbar.Item href="/features">Features</Navbar.Item>
<Navbar.Item href="/pricing">Pricing</Navbar.Item>
</Navbar.Content>
</Navbar.Header>
</Navbar>
);
}The
RouterProvidernavigatesignature differs slightly per framework — see React Aria's client-side routing guide for Next.js, React Router, TanStack Router, Remix, and others.
navigate callback (per-Navbar)When you don't have (or don't want) a global provider, pass your router's push function directly to Navbar. Every Navbar.Item / Navbar.MenuItem with an href routes through it. An explicit navigate prop always takes precedence over any global RouterProvider — useful when a navbar needs a different router (e.g. an external shell app).
"use client";
import { useRouter } from "next/navigation";
import { Navbar } from "@heroui-pro/react";
export function AppNavbar() {
const router = useRouter();
return (
<Navbar navigate={router.push}>
<Navbar.Header>
<Navbar.Brand>Acme</Navbar.Brand>
<Navbar.Content>
<Navbar.Item href="/features">Features</Navbar.Item>
<Navbar.Item href="/pricing">Pricing</Navbar.Item>
</Navbar.Content>
</Navbar.Header>
</Navbar>
);
}import { useNavigate } from "react-router";
import { Navbar } from "@heroui-pro/react";
export function AppNavbar() {
const navigate = useNavigate();
return (
<Navbar navigate={navigate}>
{/* ... */}
</Navbar>
);
}import { useRouter } from "@tanstack/react-router";
import { Navbar } from "@heroui-pro/react";
export function AppNavbar() {
const router = useRouter();
return (
<Navbar navigate={(href) => router.navigate({ to: href })}>
{/* ... */}
</Navbar>
);
}render prop for a custom link componentSince Navbar.Item and Navbar.MenuItem are polymorphic, you can swap the rendered element entirely to use a framework-specific <Link> component (preserving prefetch, scroll restoration, and any router-level behaviors):
import Link from "next/link";
import { Navbar } from "@heroui-pro/react";
export function AppNavbar() {
return (
<Navbar>
<Navbar.Header>
<Navbar.Content>
<Navbar.Item
href="/features"
render={(props) => <Link href="/features" {...props} />}
>
Features
</Navbar.Item>
</Navbar.Content>
</Navbar.Header>
</Navbar>
);
}Same works for Navbar.MenuItem in the mobile menu and for React Router's Link, TanStack Router's Link, etc.
Combine both approaches if you like —
renderowns the element/prefetch, andnavigateis used as the fallback for programmatic navigations (e.g. closing the mobile menu and pushing to the href).
External URLs (starting with http:// or https://) are automatically opened in a new tab via window.open(href, "_blank", "noopener,noreferrer"). For internal links that need a full page reload instead of client-side navigation, use the forceReload prop:
<Navbar.Item href="https://github.com/heroui-inc/heroui">GitHub</Navbar.Item>
<Navbar.Item href="/legacy-page" forceReload>Legacy page</Navbar.Item>Navigation resolution order: an explicit
navigateprop wins, then anavigateinherited from an enclosingAppLayout, then a global React AriaRouterProvider, and finally the browser's default navigation if none are present.
Use the position prop to control how the navbar is anchored:
"sticky" (default) — sticks to the top of its scroll container (sticky top-0)"static" — flows inline with the page"floating" — sticky, but detached from the edges with rounded corners, margin, border, and a shadow<Navbar position="floating" maxWidth="xl">…</Navbar>Use the useNavbar hook inside children of Navbar for programmatic access to the menu state and scroll-hidden state:
import { useNavbar } from "@heroui-pro/react";
function CloseMenuButton() {
const { isMenuOpen, setMenuOpen } = useNavbar();
return (
<Button onPress={() => setMenuOpen(false)} isDisabled={!isMenuOpen}>
Close menu
</Button>
);
}.navbar — Root <nav> element. Flex column, bg-background, z-40..navbar--sticky — Sticky to the top of the scroll container..navbar--static — Inline positioning..navbar--floating — Sticky, detached with rounded-2xl, border, shadow-surface, and mx-2..navbar[data-hidden="true"] — Applied while the navbar is hidden via hideOnScroll..navbar[data-menu-open="true"] — Applied while the mobile menu is open..navbar__header — Horizontal bar wrapper. flex items-center gap-4 px-6, clamped by --navbar-max-width and --navbar-height..navbar__header--max-sm|md|lg|xl|2xl|full — Sets --navbar-max-width to 640px / 768px / 1024px / 1280px / 1536px / 100%..navbar__header--sm|md|lg — Size variants that tune --navbar-height and header padding..navbar__brand — Logo / site-title container. flex shrink-0 items-center gap-2..navbar__content — Horizontal group of items. flex items-center gap-1..navbar__spacer — Flex-grow gap that pushes sibling content to the edges..navbar__item — Nav link/button. text-muted text-sm, hover → text-foreground, rounded-lg..navbar__item--sm|lg — Size variants for items (padding + font size)..navbar__item[data-current="true"] — Applied when isCurrent is true; bumps to text-foreground. Also sets aria-current="page"..navbar__label — Truncated text inside items..navbar__separator — Vertical decorative divider (h-6 self-center)..navbar__menu-toggle — Hamburger button (size-9). Toggles between hamburger and close icon via ::before/::after pseudo-elements..navbar__menu-toggle--sm|lg — Size variants..navbar__menu-toggle-icon — Inner span housing the animated pseudo-element lines..navbar__menu — Mobile dropdown menu. flex flex-col gap-1 overflow-y-auto px-6 pb-6 pt-2. Height animates between 0 and calc(100dvh - var(--navbar-height))..navbar__menu-item — Individual mobile menu item. text-foreground text-base font-medium, hover → bg-default..navbar__menu-item--sm|lg — Size variants..navbar__menu-item[data-current="true"] — Current mobile menu item (bg-default).--navbar-height — Height of the horizontal bar (default: 4rem; 3rem for sm; 5rem for lg). Can also be set via the height prop on Navbar.--navbar-max-width — Max content width inside the header (default: 1024px, overridable via maxWidth).--navbar-transition-duration — Reserved for future transitions (default: 300ms).--spacing — Tailwind v4 base spacing token. Override on the navbar root (or a wrapper) to uniformly scale all internal paddings, gaps, and icon sizes.<nav> landmark. Add an aria-label when multiple navigation regions share the page.Navbar.Item with isCurrent sets aria-current="page" automatically.Navbar.MenuToggle is backed by RAC ToggleButton; its selected state is wired to isMenuOpen. Customize the screen-reader label via the srLabel prop.prefers-reduced-motion preference.The root <nav> landmark and the context provider. Accepts all <nav> props.
| Prop | Type | Default | Description |
|---|---|---|---|
position | "sticky" | "static" | "floating" | "sticky" | How the navbar is anchored to the page. |
size | "sm" | "md" | "lg" | "md" | Applies the matching size variants to the header, items, and menu toggle. |
maxWidth | "sm" | "md" | "lg" | "xl" | "2xl" | "full" | "lg" | Caps the header's content width via --navbar-max-width. |
height | string | "4rem" | CSS height for the bar. Sets --navbar-height inline. |
hideOnScroll | boolean | false | Hide the navbar when scrolling down and reveal on scroll up. Uses a spring transform so layout stays intact. |
parentRef | RefObject<HTMLElement | null> | window | Scroll container used by hideOnScroll. Defaults to the window. |
isMenuOpen | boolean | — | Controlled mobile menu open state. |
defaultMenuOpen | boolean | false | Initial mobile menu open state (uncontrolled). |
onMenuOpenChange | (isOpen: boolean) => void | — | Callback when the mobile menu state changes. |
shouldBlockScroll | boolean | true | Lock body scroll while the mobile menu is open. |
navigate | (href: string) => void | — | Programmatic navigation function used by Navbar.Item / Navbar.MenuItem when pressed. If omitted, the Navbar defers to a global React Aria RouterProvider when present, then to native browser navigation. |
Horizontal bar wrapper. Renders a <header> with the header size and max-width slot classes applied.
Logo / site-title container. Polymorphic — accepts a render prop to customize the rendered element. Renders a <div> by default.
Horizontal group of nav items. Renders a <div>.
A single nav link or action. Renders an <a> when href is set, otherwise a <button>. Polymorphic via the render prop.
| Prop | Type | Default | Description |
|---|---|---|---|
href | string | — | Destination URL. Uses the parent Navbar's navigate (or a global React Aria RouterProvider) for client-side routing, or the browser's default navigation as a fallback. External URLs (http://, https://) open in a new tab. |
isCurrent | boolean | false | Marks the item as the current page. Sets aria-current="page" and data-current="true". |
forceReload | boolean | false | Skip the navigate callback and use window.location.href for this item. |
render | (props) => ReactElement | — | Override the rendered element (e.g. to render a Next.js / React Router <Link>). |
Truncated text span for use inside Navbar.Item.
Vertical divider. Wraps HeroUI Separator with orientation="vertical".
Flex-grow spacer that pushes surrounding content to opposite ends of the header.
Hamburger button for the mobile menu. Wraps RAC ToggleButton; its selected state is bound to isMenuOpen.
| Prop | Type | Default | Description |
|---|---|---|---|
srLabel | string | "Toggle navigation menu" | Screen-reader label for the toggle. |
children | ReactNode | — | Custom icon. When omitted, the built-in animated hamburger/close icon is used. |
Animated mobile dropdown. Only renders when isMenuOpen is true. Fills the viewport below the navbar with calc(100dvh - var(--navbar-height)).
An individual item inside Navbar.Menu. Same API surface as Navbar.Item — but pressing an item automatically closes the mobile menu.
| Prop | Type | Default | Description |
|---|---|---|---|
href | string | — | Destination URL. Same client-side routing rules as Navbar.Item. |
isCurrent | boolean | false | Marks the item as the current page. |
forceReload | boolean | false | Skip the navigate callback and use window.location.href. |
render | (props) => ReactElement | — | Override the rendered element. |
A hook for reading and mutating navbar state from inside Navbar's children.
const { height, isHidden, isMenuOpen, setMenuOpen, navigate } = useNavbar();| Property | Type | Description |
|---|---|---|
height | string | Current navbar height (as passed via the height prop). |
isHidden | boolean | Whether the navbar is currently hidden via hideOnScroll. |
isMenuOpen | boolean | Whether the mobile menu is currently open. |
setMenuOpen | (open: boolean) => void | Programmatically open/close the mobile menu. |
navigate | ((href: string) => void) | undefined | The navigation function passed to Navbar, if any. |