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" }}
    />
  );
}