Navbar
A composable top navigation bar with hide-on-scroll, responsive mobile menu, and client-side routing support
Import
import { Navbar } from '@darkcode-ui/react';Usage
"use client";
import {Button, Navbar} from "@darkcode-ui/react";
import {Sparkles} from "@gravity-ui/icons";
Anatomy
Import the Navbar component and access all parts using dot notation.
import { Navbar } from '@darkcode-ui/react';
export default () => (
<Navbar>
<Navbar.Header>
<Navbar.Brand />
<Navbar.MenuToggle />
<Navbar.Content>
<Navbar.Item />
<Navbar.Label />
<Navbar.Separator />
<Navbar.Spacer />
</Navbar.Content>
</Navbar.Header>
<Navbar.Menu>
<Navbar.MenuItem />
</Navbar.Menu>
</Navbar>
)Docs Site
A docs-site style navbar with a search bar, theme segment, and responsive mobile menu.
"use client";
import {Navbar, SearchField, ToggleButton, ToggleButtonGroup} from "@darkcode-ui/react";
import {Display, Moon, Sparkles, Sun} from "@gravity-ui/icons";
With Dropdowns
SaaS-style navbar with a team switcher, user dropdown, and mobile menu.
"use client";
import {
Avatar,
Button,Dashboard
Breadcrumb-style dashboard navbar built with InlineSelect for the workspace, project, and timezone selectors.
"use client";
import {Button, InlineSelect, ListBox, Navbar} from "@darkcode-ui/react";
import {Bell, ChevronRight, Sparkles} from "@gravity-ui/icons";
Compact
A dense navbar tuned via --spacing and height overrides for a Luma-style compact layout.
"use client";
import type {CSSProperties} from "react";
import {Button, Navbar} from "@darkcode-ui/react";With Menu
Responsive navbar with a mobile hamburger toggle and animated dropdown menu.
"use client";
import {Button, Navbar} from "@darkcode-ui/react";
import {Sparkles} from "@gravity-ui/icons";
Hide on Scroll
Pass hideOnScroll to hide the navbar when the user scrolls down and reveal it on scroll up.
"use client";
import {Button, Navbar} from "@darkcode-ui/react";
import {Sparkles} from "@gravity-ui/icons";
import {useRef} from "react";Centered
Use justify on Navbar.Content to lay out the bar as brand · centered nav · actions
without manual spacers. justify="center" lets the group grow and center, while
justify="end" pushes the actions to the far edge.
"use client";
import {Button, Navbar} from "@darkcode-ui/react";
import {Sparkles} from "@gravity-ui/icons";
Responsive Mobile Menu
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.
Compact Density
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>--spacingscales every Tailwind spacing utility (gap-*,p-*,size-*) inside the navbarheightoverrides the internal--navbar-heightCSS variablesize="sm"applies the built-in compact text + padding variants
Client-Side Routing
Navbar.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 two ways to integrate client-side routing.
Option 1 — navigate callback (recommended)
Pass your router's push function to Navbar. Every Navbar.Item / Navbar.MenuItem with an href will route through it, preventing full-page reloads.
"use client";
import { useRouter } from "next/navigation";
import { Navbar } from "@darkcode-ui/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>
);
}Option 2 — render prop for a custom link component
Since 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 "@darkcode-ui/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>
);
}External Links and Force Reload
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/DarkCode-Developers/darkcode-ui">GitHub</Navbar.Item>
<Navbar.Item href="/legacy-page" forceReload>Legacy page</Navbar.Item>If no
navigatefunction is provided,hreffalls back to the browser's default navigation.
Positioning
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>Appearance
isBlurred(defaulttrue) — a frosted-glass backdrop: a translucent background plusbackdrop-blur. PassisBlurred={false}for a solid bar.isBordered— adds a bottom border.- Elevate on scroll — once the scroll container has moved, the navbar gains a subtle shadow
(
data-scrolled="true"). Floating navbars keep their own shadow instead.
<Navbar isBordered isBlurred>…</Navbar>
<Navbar isBlurred={false}>…</Navbar>Scroll Behavior
onScrollPositionChange(position)— called with the scroll offset as the container scrolls.disableScrollHandler— skip the internal scroll listener entirely (no hide / elevate / callback).disableAnimation— opt out of the menu, toggle, and hide-on-scroll transitions.
<Navbar hideOnScroll onScrollPositionChange={(y) => console.log(y)}>…</Navbar>Programmatic Control
Use the useNavbar hook inside children of Navbar for programmatic access to the menu state and scroll-hidden state:
import { useNavbar } from "@darkcode-ui/react";
function CloseMenuButton() {
const { isMenuOpen, setMenuOpen } = useNavbar();
return (
<Button isDisabled={!isMenuOpen} onPress={() => setMenuOpen(false)}>
Close menu
</Button>
);
}Styling
Customizing the component classes
To customize the Navbar component classes, you can use the @layer components directive.
Learn more.
@layer components {
.navbar {
--navbar-height: 3.5rem;
}
.navbar__item {
@apply font-semibold;
}
}DarkCode UI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.
CSS Classes
The Navbar component uses these CSS classes (View source styles):
Base & Variant Classes
.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 withrounded-2xl,border,shadow-surface, andmx-2..navbar--bordered— Adds a bottom border..navbar--blurred— Translucent background +backdrop-blur(applied by default; falls back to a solid background whenbackdrop-filteris unsupported)..navbar--no-animation— Disables transitions/animations..navbar[data-hidden="true"]— Applied while the navbar is hidden viahideOnScroll..navbar[data-scrolled="true"]— Applied once the scroll container has scrolled (adds an elevate shadow)..navbar[data-menu-open="true"]— Applied while the mobile menu is open.
Layout Classes
.navbar__header— Horizontal bar wrapper, clamped by--navbar-max-widthand--navbar-height..navbar__header--max-sm|md|lg|xl|2xl|full— Sets--navbar-max-width..navbar__header--sm|lg— Size variants that tune header padding..navbar__brand— Logo / site-title container..navbar__content— Horizontal group of items..navbar__content--center|end— Justify the content group (via thejustifyprop)..navbar__spacer— Flex-grow gap that pushes sibling content to the edges.
Item Classes
.navbar__item— Nav link/button..navbar__item--sm|lg— Size variants for items..navbar__item[data-current="true"]— Applied whenisCurrentis true. Also setsaria-current="page"..navbar__label— Truncated text inside items..navbar__separator— Vertical decorative divider.
Menu Classes
.navbar__menu-toggle— Hamburger button. Morphs between hamburger and close icon..navbar__menu-toggle--sm|lg— Size variants..navbar__menu-toggle-icon— Inner span housing the animated lines..navbar__menu— Mobile dropdown menu, fillscalc(100dvh - var(--navbar-height)). Carriesdata-state="open"|"closed"to drive enter/exit animations..navbar__menu-item— Individual mobile menu item..navbar__menu-item--sm|lg— Size variants..navbar__menu-item[data-current="true"]— Current mobile menu item.
CSS Variables
--navbar-height— Height of the horizontal bar (default4rem;3remforsm;5remforlg). Can also be set via theheightprop.--navbar-max-width— Max content width inside the header (default1024px, overridable viamaxWidth).--navbar-transition-duration— Hide-on-scroll transition duration (default300ms).--spacing— Tailwind v4 base spacing token. Override on the navbar root to uniformly scale internal paddings, gaps, and icon sizes.
API Reference
Navbar
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. |
isBlurred | boolean | true | Frosted-glass backdrop (translucent background + backdrop-blur). |
isBordered | boolean | false | Add a bottom border. |
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. |
disableScrollHandler | boolean | false | Skip the internal scroll listener (no hide / elevate / position callback). |
onScrollPositionChange | (position: number) => void | — | Called with the scroll offset whenever the scroll container scrolls. |
disableAnimation | boolean | false | Opt out of menu, toggle, and hide-on-scroll transitions. |
parentRef | RefObject<HTMLElement | null> | window | Scroll container used by hideOnScroll / scroll callbacks. 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. |
Navbar.Header
Horizontal bar wrapper. Renders a <header> with the header size and max-width slot classes applied.
Navbar.Brand
Logo / site-title container. Polymorphic — accepts a render prop to customize the rendered element. Renders a <div> by default.
Navbar.Content
Horizontal group of nav items. Renders a <div>.
| Prop | Type | Default | Description |
|---|---|---|---|
justify | "start" | "center" | "end" | "start" | Align the group within the header. center grows and centers; end pushes the group to the far edge. |
Navbar.Item
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 for client-side routing, or the browser's default navigation as a fallback. External URLs open in a new tab. |
isCurrent | boolean | false | Marks the item as the current page. Sets aria-current="page" and data-current="true". |
isActive | boolean | false | Alias for isCurrent. |
forceReload | boolean | false | Skip the navigate callback and use window.location.href for this item. |
render | (props) => ReactElement | — | Override the rendered element. |
Navbar.Label
Truncated text span for use inside Navbar.Item.
Navbar.Separator
Vertical divider. Wraps the DarkCode UI Separator with orientation="vertical".
Navbar.Spacer
Flex-grow spacer that pushes surrounding content to opposite ends of the header.
Navbar.MenuToggle
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. |
Navbar.Menu
Animated mobile dropdown. Only renders when isMenuOpen is true. Fills the viewport below the navbar with calc(100dvh - var(--navbar-height)).
Navbar.MenuItem
An individual item inside Navbar.Menu. Same API surface as Navbar.Item — but pressing an item automatically closes the mobile menu.
useNavbar
A hook for reading and mutating navbar state from inside Navbar's children.
const { height, isHidden, isScrolled, 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. |
isScrolled | boolean | Whether the scroll container has scrolled past the top. |
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. |
Accessibility
- Rendered as a
<nav>landmark. Add anaria-labelwhen multiple navigation regions share the page. Navbar.ItemwithisCurrent(orisActive) setsaria-current="page"automatically.Navbar.MenuToggleis backed by RACToggleButton; its selected state is wired toisMenuOpen. Customize the screen-reader label via thesrLabelprop.- While the mobile menu is open, focus is contained within it, the first item is focused on open, and focus is restored to the toggle on close.
- The mobile menu closes on
Escapeand auto-closes when the viewport grows to the desktop breakpoint. - Animations respect the user's
prefers-reduced-motionpreference, and can be disabled entirely withdisableAnimation.