Navbar
since v13.2.0General horizontal navigation bar — reusable as an app topbar or a landing-page
header. Layout: brand (left) · nav links · actions (right) — or pass
navAlign="center" to float the links centered in the bar. The active link
carries the ink treatment (text-ink-1 + font-medium + a 2px underline),
never the brand voltage — a Navbar's only brand moment is a consumer-passed
Button variant="brand" in actions.
Below md the links collapse into a Radix Dialog sheet (mobile="sheet",
default). Radix owns focus-trap, scroll-lock, ESC, return-focus, and
aria-modal; the sheet escalates its z-index when stacked inside another modal
via the shared {@link useModalDepth}/{@link nestedModalZ} helpers. Pass
mobile="none" to keep links inline at every width with no trigger/sheet.
Install
Add the package and import the component.
pnpm add @hey-mike/tungstenpnpm add @hey-mike/tungstenimport { Navbar } from '@hey-mike/tungsten';import { Navbar } from '@hey-mike/tungsten';Preview
Same fixtures used by the visual-regression suite.
Usage
apps/docs/app/snapshots/navbar/page.tsx
import { Button, Navbar } from '@hey-mike/tungsten';
import { VariantGrid } from '../_components/VariantGrid';
export default function NavbarSnapshot() {
const items = [
{ id: 'home', label: 'Home', href: '#' },
{ id: 'work', label: 'Work', href: '#' },
{ id: 'about', label: 'About', href: '#' },
];
return (
<VariantGrid
title="Navbar"
variants={[
{
label: 'default (active: Work)',
node: (
<Navbar
brand={<span className="text-ink-1 font-semibold">Acme</span>}
items={items}
activeId="work"
actions={<Button variant="brand">Sign up</Button>}
/>
),
},
]}
/>
);
}
import { Button, Navbar } from '@hey-mike/tungsten';
import { VariantGrid } from '../_components/VariantGrid';
export default function NavbarSnapshot() {
const items = [
{ id: 'home', label: 'Home', href: '#' },
{ id: 'work', label: 'Work', href: '#' },
{ id: 'about', label: 'About', href: '#' },
];
return (
<VariantGrid
title="Navbar"
variants={[
{
label: 'default (active: Work)',
node: (
<Navbar
brand={<span className="text-ink-1 font-semibold">Acme</span>}
items={items}
activeId="work"
actions={<Button variant="brand">Sign up</Button>}
/>
),
},
]}
/>
);
}
Props
Surface specific to <Navbar />.
| Prop | Type | Default | Description |
|---|---|---|---|
| brand | ReactNode | — | Logo / wordmark slot, rendered at the left of the bar. No default. |
| items | NavItemSpec[] | [] | Nav entries — links (href) or actions (onClick). See {@link NavItemSpec}. |
| activeId | string | — | id of the active item; gets aria-current="page" + the ink active treatment. |
| actions | ReactNode | — | Right-side slot: CTAs, account menu, search, theme toggle. The only place a consumer-passed brand-voltage Button belongs on a Navbar. |
| linkComponent | ElementType | — | Element used to render link items (those with href). Default 'a'.
Pass a router link (e.g. Next.js <Link>) for client-side navigation. |
| ariaLabel | string | Main | Accessible label for the nav landmark. Default 'Main'. |
| sticky | boolean | false | Opt into sticky top-0. Default false — the bar is otherwise layout-neutral
(full-width, no baked max-width / blur / shadow). |
| mobile | "sheet" | "none" | sheet | Mobile collapse behaviour below md. 'sheet' (default) shows a hamburger
that opens a Radix Dialog sheet; 'none' renders no trigger/sheet. |
| navAlign | "center" | "start" | start | Horizontal (main-axis) placement of the nav links — not vertical alignment.
'start' (default) keeps them inline right of the brand; 'center' floats them
centered in the bar (brand left, actions right) via absolute positioning at
md+. Centering has no collision guard — it assumes the brand + actions leave
room for the links, so it suits a short link set. |
| className | string | — | — |