/// Layout
Sidebar
A left navigation rail of grouped items — mono uppercase group labels over sans links, with an accent rule on the active item.
import { Sidebar } from "@protocore/pds";Basics
Compose Sidebar from Sidebar.Groups, each a Sidebar.GroupLabel (mono uppercase) over a run of Sidebar.Items. The current item takes active, which inks it and grows a 2px accent left rule.
Collapsible groups
Set collapsible on a Sidebar.Group and give it a label — the label becomes a Radix Collapsible trigger with a chevron, and the items expand and collapse beneath it. Control it with open/defaultOpen/onOpenChange.
When to use it
Sidebar is the persistent left rail for application wayfinding — a console or dashboard with a fixed set of destinations. It is the primitive; AppShell places it (a fixed column on desktop, an off-canvas drawer below 860px), so you rarely position it yourself. Use TopBar instead for a marketing or top-level site nav, and Tabs for switching views *within* a single page rather than navigating between pages. Sidebar.Item renders an <a> by default; pass asChild to wrap a router <Link> so client routing and active state stay in sync.
Usage
Do
- Group related destinations under a GroupLabel so the rail scans quickly.
- Mark exactly one Item active per view to anchor the user.
- Use asChild on Sidebar.Item to wrap your router's Link component.
Don't
- Use a Sidebar to switch tabs within one page — that is the Tabs component.
- Leave more than one Item active at a time.
- Nest another scrolling region inside the rail; let AppShell own the layout.
Accessibility
| Keys | Action |
|---|---|
| Tab | Move focus to the next item or group trigger |
| Shift + Tab | Move focus to the previous item or trigger |
| Enter | Follow the focused item, or toggle a collapsible group's trigger |
| Space | Toggle the focused collapsible group trigger |
- The root renders an `<aside>` — give it an `aria-label` so it is a labelled complementary landmark.
- The active item sets `aria-current="page"`, so the current location is exposed, not just coloured.
- Collapsible groups use Radix Collapsible: the trigger exposes its expanded/collapsed state to assistive tech.
Sidebar.Group props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | |
collapsible | boolean | — | Make the group collapsible. Its `label` becomes the toggle; children collapse. |
defaultOpen | boolean | true | Uncontrolled initial open state (collapsible only). Default open. |
label | ReactNode | — | Group heading. Rendered as the trigger when `collapsible`; otherwise use `Sidebar.GroupLabel`. |
onOpenChange | ((open: boolean) => void) | — | Open-state change callback (collapsible only). |
open | boolean | — | Controlled open state (collapsible only). |
style | CSSProperties | — |
Sidebar.GroupLabel props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | |
style | CSSProperties | — |
Sidebar.Item props
| Prop | Type | Default | Description |
|---|---|---|---|
active | boolean | — | Mark as the current item — inks the label and shows the accent left rule. |
asChild | boolean | — | Render into a passed child (e.g. a router `<Link>`) instead of an `<a>`. |
className | string | — | |
style | CSSProperties | — |