Navigation
Navigation renders semantic page or app navigation with native nav, anchor, and button elements. Use it for product sections, dashboards, and sidebar menus. Use Tabs instead for document-style tab strips.
Plain
import { Navigation } from "density-base-ui";
import { useState } from "react";
const items = [
{ id: "overview", label: "Overview" },
{ id: "services", label: "Services" },
{ id: "alerts", label: "Alerts" },
{
id: "settings",
label: "Settings",
href: "/docs/components/navigation",
},
];
export default function NavigationExample() {
const [activeId, setActiveId] = useState("overview");
return (
<Navigation
activeId={activeId}
aria-label="Product navigation"
items={items}
onActiveIdChange={setActiveId}
/>
);
}Badges on the right
import { Badge, Navigation } from "density-base-ui";
import { useState } from "react";
const items = [
{ id: "overview", label: "Overview", childrenEnd: <Badge>2</Badge> },
{ id: "services", label: "Services", childrenEnd: <Badge>8</Badge> },
{ id: "alerts", label: "Alerts", childrenEnd: <Badge>3</Badge> },
{ id: "settings", label: "Settings", childrenEnd: <Badge>1</Badge> },
];
export default function NavigationBadgesExample() {
const [activeId, setActiveId] = useState("overview");
return (
<Navigation
activeId={activeId}
aria-label="Navigation with badges"
items={items}
onActiveIdChange={setActiveId}
/>
);
}Icons on the left
import { Navigation } from "density-base-ui";
import { Bell, FileText, LayoutDashboard, Settings } from "lucide-react";
import { useState } from "react";
const items = [
{
id: "overview",
label: "Overview",
childrenStart: <LayoutDashboard aria-hidden="true" size={16} />,
},
{
id: "documents",
label: "Documents",
childrenStart: <FileText aria-hidden="true" size={16} />,
},
{
id: "alerts",
label: "Alerts",
childrenStart: <Bell aria-hidden="true" size={16} />,
},
{
id: "settings",
label: "Settings",
childrenStart: <Settings aria-hidden="true" size={16} />,
},
];
export default function NavigationIconsExample() {
const [activeId, setActiveId] = useState("overview");
return (
<Navigation
activeId={activeId}
aria-label="Navigation with icons"
items={items}
onActiveIdChange={setActiveId}
/>
);
}Size
import { useState, type ComponentProps } from "react";
import { Navigation, View } from "density-base-ui";
const items = [
{ id: "overview", label: "Overview" },
{ id: "settings", label: "Settings" },
];
function SizeNavigation({
size,
}: {
size: ComponentProps<typeof Navigation>["size"];
}) {
const [activeId, setActiveId] = useState("overview");
return (
<Navigation
activeId={activeId}
aria-label={`${size} navigation`}
items={items}
onActiveIdChange={setActiveId}
size={size}
/>
);
}
export default function NavigationSizeExample() {
return (
<View align="start" gap="lg" layout="grid" padding={false}>
<SizeNavigation size="2xs" />
<SizeNavigation size="xs" />
<SizeNavigation size="sm" />
<SizeNavigation size="md" />
<SizeNavigation size="lg" />
<SizeNavigation size="xl" />
<SizeNavigation size="2xl" />
<SizeNavigation size="3xl" />
</View>
);
}Items with href render anchors and preserve normal link navigation while notifying onActiveIdChange. Items without href render buttons for in-page navigation. The active item uses secondary emphasis while inactive items use ghost-primary emphasis; its selected state remains separate from hover, active, and keyboard focus.
Vertical navigation
import { Badge, Navigation } from "density-base-ui";
import { Activity, Gauge, TriangleAlert, Zap } from "lucide-react";
import { useState } from "react";
const items = [
{
id: "traffic",
label: "Traffic",
childrenStart: <Activity aria-hidden="true" size={16} />,
},
{
id: "latency",
label: "Latency",
childrenStart: <Gauge aria-hidden="true" size={16} />,
},
{
id: "errors",
label: "Errors",
childrenStart: <TriangleAlert aria-hidden="true" size={16} />,
childrenEnd: <Badge>2</Badge>,
},
{
id: "capacity",
label: "Capacity",
childrenStart: <Zap aria-hidden="true" size={16} />,
},
];
export default function NavigationVerticalExample() {
const [activeId, setActiveId] = useState("traffic");
return (
<Navigation
activeId={activeId}
aria-label="Metrics navigation"
items={items}
onActiveIdChange={setActiveId}
orientation="vertical"
style={{ maxWidth: "14rem" }}
/>
);
}| Prop | Values | Required | Default | Behavior | Description |
|---|---|---|---|---|---|
activeId | string | Required | — | — | — |
depth | 1, 2, 3, 4, 5, 6, 7 | Not required | — | Attribute: data-dn-depth | — |
gap | 2xs, xs, sm, md, lg, xl, 2xl, 3xl, none | Not required | — | Attribute: data-dn-gap | — |
items | NavigationItem[] | Required | — | — | — |
onActiveIdChange | (id: string) => void | Not required | — | — | — |
orientation | vertical, horizontal | Not required | "horizontal" | Attribute: data-dn-orientation | — |
padding | false, true | Not required | true | — | — |
size | 2xs, xs, sm, md, lg, xl, 2xl, 3xl | Not required | — | Attribute: data-dn-size | — |
variant | button, physical-tab, underline-tabs | Not required | "button" | — | — |
This component also accepts props from native APIs. They are passed through and intentionally kept out of this focused Density API table.