Nav
An app's sections. The current one sits under a cobalt band that stretches to it, across groups too. Items are links with href or buttons; nested items open a list under their parent. In AppShell's rail only the icons show, and the label appears beside each on hover and focus.
Loading the live example…
"use client"
import { ChartNoAxesColumn, FileText, PartyPopper, Plus, UserRound, Warehouse } from "lucide-react"
import { useState } from "react"
import { Nav, NavIdentity, type NavGroup } from "@/components/keyline/ui/nav"
const GROUPS: NavGroup[] = [
{
label: "Sales",
items: [
{ value: "orders", label: "Orders", count: 11, icon: <FileText size={16} aria-hidden="true" /> },
{ value: "clients", label: "Clients", count: 64, icon: <UserRound size={16} aria-hidden="true" /> },
{
value: "reports",
label: "Reports",
icon: <ChartNoAxesColumn size={16} aria-hidden="true" />,
items: [
{ value: "reports-weekly", label: "Weekly sales" },
{ value: "reports-quarter", label: "Quarter to date" },
],
},
],
},
{
label: "Office",
items: [
{ value: "warehouse", label: "Warehouse", icon: <Warehouse size={16} aria-hidden="true" /> },
{ value: "parties", label: "Party planning", count: 2, icon: <PartyPopper size={16} aria-hidden="true" /> },
{ value: "hr", label: "Human resources", disabled: true, icon: <Plus size={16} aria-hidden="true" /> },
],
},
]
const TITLES: Record<string, string> = {
orders: "11 open orders, 2 held",
clients: "64 active clients",
"reports-weekly": "Weekly sales: 1,810 reams",
"reports-quarter": "Quarter to date: 19,880 reams",
warehouse: "88 pallets on the floor",
parties: "Two parties this month. Angela has the budget.",
}
export function OfficeSidebar() {
const [view, setView] = useState("orders")
return (
<div className="grid gap-4 sm:grid-cols-[240px_1fr]">
<Nav
label="Scranton branch"
value={view}
onValueChange={setView}
groups={GROUPS}
header={<NavIdentity mark="DM" title="Scranton" meta="Branch 0418" />}
/>
<p role="status" className="m-0 self-start text-[14px] text-kl-ink-2">
{TITLES[view]}
</p>
</div>
)
}Installation
npx shadcn@latest add @keyline-ui/navRun it where your components.json is. The first time, map the @keyline-ui registry: one command, in Installation.
Usage
import { Nav, type NavGroup } from "@/components/keyline/ui/nav"<Nav
label="Scranton branch"
value={view}
onValueChange={setView}
groups={[{ label: "Sales", items: [{ value: "orders", label: "Orders", count: 11 }] }]}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
items · groups | NavItem[] · NavGroup[] | Default — | A flat list, or labelled sections divided by a heavy seam. |
value | string | Default — | The current item. |
onValueChange | (value: string) => void | Default — | For button items. Link items navigate. |
label | string | Default — | Names the navigation landmark. |
header · footer | ReactNode | Default — | At the top and bottom of the column. NavIdentity is a mark, title and meta line. |
orientation | "vertical" | "horizontal" | "responsive" | Default "vertical" | responsive is a column under 300px of its own width, a row above. |
layout | "control" | "cell" | Default "control" | cell sits inside another frame, such as AppShell's sidebar. |
NavItem | { value, label, href?, icon?, count?, items?, disabled?, action? } | Default — | items nests links; action is a cell for the row's own commands, usually a NavAction opening a Menu. |
This site's component list and page contents are Keyline Nav.