Sidebar
The Sidebar is the layout shell — a fixed-width column with the panel
background and a right border. Compose with NavSection and NavItem to get
the standard ShipIt sidebar shape.
NavSection groups a labeled cluster of NavItems under an eyebrow heading.
By default the eyebrow is static, but pass collapsible and the eyebrow
becomes a button that toggles the body — useful when the navigation gets
long enough that users want to fold sections away.
Default#
Collapsible sections#
Pass collapsible to make a NavSection fold its children behind an
expand/collapse button. The eyebrow becomes a <button> with
aria-expanded, the body is removed when closed, and a ▾/▸ chevron
mirrors the state. Use defaultOpen for uncontrolled, or open +
onOpenChange to control state from a parent.
The optional icon slot renders next to the eyebrow — pair it with
<IconGlyph /> from @ship-it-ui/icons for consistent iconography.
Nested sections#
NavSection accepts an indent prop (in pixels) that pads the body and
draws a subtle left rail. Use it when one section nests inside another so
the hierarchy reads at a glance — without the indent, an inner eyebrow is
visually identical to the outer one.
Compose by setting indent on each level: the outer section indents its
body, the inner section indents its leaves further, and the rails stack
into a tree.
Props#
Sidebar#
| Prop | Type | Default | Description |
|---|---|---|---|
| width | number | undefined | 240 | Width in pixels. Default 240. |
NavSection#
| Prop | Type | Default | Description |
|---|---|---|---|
| label * | ReactNode | — | Eyebrow heading. Rendered uppercase, mono, dim. |
| icon | ReactNode | — | Optional leading glyph or icon node next to the eyebrow. |
| action | ReactNode | — | Optional trailing element next to the heading (e.g., a `+` add affordance). |
| collapsible | boolean | undefined | false | When true, the eyebrow becomes a button that toggles the body. The body is hidden when closed. Default `false` — the eyebrow stays static. |
| defaultOpen | boolean | undefined | true | Uncontrolled initial open state. Default `true`. Ignored when `open` is provided. |
| open | boolean | undefined | — | Controlled open state. |
| onOpenChange | ((open: boolean) => void) | undefined | — | Fires when the open state changes. |
| indent | number | undefined | 0 | Pixel indent applied to the body. Useful when this section nests other sections — the indent visually anchors children to the eyebrow above. A subtle left rail is drawn alongside the indent. Default `0`. |
NavItem#
| Prop | Type | Default | Description |
|---|---|---|---|
| icon | ReactNode | — | Left-side glyph or icon node. |
| label * | ReactNode | — | Visible label. |
| active | boolean | undefined | — | Highlights the row in the accent palette. |
| badge | ReactNode | — | Optional trailing badge text. |
| disabled | boolean | undefined | — | Disabled / read-only display. |
| href | string | undefined | — |