Components

Sidebar

The dashboard rail. It collapses to icons and becomes a drawer on small screens.

Web
import SidebarRoot from "swshd/Sidebar/Root";

Sidebar is the dashboard rail: a floating rounded surface of pill rows. This site uses it — the navigation on the left is the component.

Web only. On native the parts render nothing; SidebarProvider and SidebarPage pass their children through.

SidebarProvider → SidebarDrawerOpener + SidebarRoot + SidebarPage. The parts:

SidebarProvider

State (collapsed / onCollapsedChange); renders no DOM.

SidebarDrawerOpener

The fixed button that opens the drawer under drawerBelow.

SidebarRoot

The rail — an <aside aria-label> fixed to the viewport's left edge.

SidebarBrand

Logo link and the collapse toggle.

SidebarNav

A <nav aria-label> group of items.

SidebarItem

A link or button pill: Icon or icon slot, label, active, external, notification.

SidebarSpacer

Pushes the second group to the bottom.

SidebarFooter

The slot below the groups — one control (a SidebarTrigger).

SidebarTrigger

A disclosure row for the footer: label, optional meta line, the built-in glyph, and expanded (aria-expanded). It opens something and closes nothing itself.

SidebarLink

An identity link using the trigger's layout: icon, label, optional meta, and an external-link glyph for new-tab destinations.

SidebarPage

The page host: the offset content column and its block <main>.

SidebarPage paints the canvas full width and offsets the page by the rail's current width, animating that offset over motion.duration.slow; inside it a 1200 px block <main> centers the page. It adds no header — pages keep their own — and clips horizontal overflow at the document. The page frame is pageInsetY = 32 px; in drawer mode the top frame is SIDEBAR_PAGE_INSET_TOP_DRAWER = 56 px.

Expanded 256 px, collapsed 64 px, rows 44 px — 48 px in the drawer. The user toggles with the brand toggle or [ (ignored while typing). Under autoCollapseBelow (1100 px) the rail starts collapsed; under drawerBelow (900 px) it is an off-canvas drawer. The icon axis is identical in both states, so glyphs do not move; collapsed items show a Tooltip. Reduced motion and automation snap every transition.

Exactly one SidebarBrand, first. Items go only inside SidebarNav; each Nav needs a label. SidebarFooter holds one control (a SidebarTrigger); nothing else renders below it.

SidebarItem, SidebarLink, and SidebarTrigger take Icon (a glyph) or icon (any node, e.g. an Avatar); icon wins when both are passed. No part accepts style: sizes come from SIDEBAR_SIZES, colors from SIDEBAR_TOKENS. Labels are strings the app translates — swshd holds no copy.

Use SidebarLink inside SidebarNav for an entity destination with the same layout as the organization selector. Pass a decorative Avatar, the translated entity name, and href. With external, pass anaccessibilityLabel that announces the destination and new-tab behavior. For a two-line name, pass the upper line as label and the lower line as a string meta; both share typography and truncate separately.

<SidebarProvider collapsed={pref} onCollapsedChange={setPref}>
  <SidebarDrawerOpener label="Open navigation" />
  <SidebarRoot label="Organization navigation">
    <SidebarBrand href="/home" label="SWSH"
      toggleLabels={{ collapse: "Collapse sidebar", expand: "Expand sidebar" }} />
    <SidebarNav label="Primary">
      <SidebarItem href="/home" label="Home" Icon={IconHome} active />
    </SidebarNav>
  </SidebarRoot>
  <SidebarPage>{children}</SidebarPage>
</SidebarProvider>

Root is an <aside aria-label>; each group a <nav aria-label>; the active item carries aria-current="page"; external items are real anchors with rel="noopener noreferrer"; the trigger is a button named by its label. The closed drawer is inert; Escape or the scrim closes an open one, moving focus back to the opener.

No part accepts a style prop; all are configured through props.

SidebarProvider

PropTypeDefaultDescription
collapsedboolean | null—Controlled collapse preference; null = no preference (breakpoint default applies).
onCollapsedChange(collapsed: boolean) => void—Fired on collapse changes.
childrenReactNode—The SidebarRoot tree (with its SidebarDrawerOpener) and the SidebarPage.

SidebarRoot

PropTypeDefaultDescription
labelstring—Accessible name of the navigation landmark.
childrenReactNode—Brand, navs, spacer, footer.
testIDstring—data-testid on web.

SidebarBrand

PropTypeDefaultDescription
hrefstring—Where the logo goes (the app's home).
LogoIconComponent—Defaults to the SWSH glyph.
labelstring—Accessible name of the logo link.
toggleLabels{ collapse: string; expand: string }—Toggle copy, translated by the app.
testIDstring—data-testid on web.
toggleTestIDstring—data-testid on the collapse toggle.

SidebarItem

PropTypeDefaultDescription
labelstring—The row's text.
IconIconComponent—A glyph sized by SIDEBAR_SIZES.icon.
iconReactNode—Any node for the icon slot instead (e.g. an Avatar); wins over Icon.
hrefstring—Makes the item a link.
externalboolean—Requires href. Opens in a new tab with the external glyph trailing; never active.
onPress() => void—Required when href is unset.
activeboolean—The current page: fill.selected backdrop and aria-current="page".
notificationnumber—A Notification count on the icon's corner.
notificationLabelstring—What the count means ("2 pending invites"); folded into the row's accessible name.
disabledboolean—Blocks interaction.
testIDstring—data-testid on web.

SidebarNav

PropTypeDefaultDescription
labelstring—aria-label of this <nav> group.
childrenReactNode—The group's SidebarItem rows.

SidebarSpacer

No props.

SidebarFooter

PropTypeDefaultDescription
childrenReactNode—One control (a SidebarTrigger).

SidebarTrigger

PropTypeDefaultDescription
labelstring—Primary text; string meta joins the default accessible name and collapsed tooltip.
IconIconComponent—A glyph sized by SIDEBAR_SIZES.icon.
iconReactNode—Any node for the icon slot instead; wins over Icon.
metaReactNode—A second line: strings match the label's typography and truncate separately; nodes render as-is.
expandedboolean—The disclosure it controls is open: the open fill and aria-expanded.
onPress() => void—Toggles the disclosure it opens.
disabledboolean—Blocks interaction.
testIDstring—data-testid on web.

SidebarLink

Import from swshd/Sidebar/Link. Shares label, Icon,icon, meta, disabled, and testID with the trigger; renders an anchor and closes the drawer on activation.

PropTypeDefaultDescription
hrefstring—Required destination URL.
externalboolean—Opens a new tab with noopener noreferrer and the external-link glyph.
accessibilityLabelstring—Accessible name and collapsed tooltip; defaults to label plus string meta, if provided.
onPress() => void—Optional activation callback.

SidebarPage

PropTypeDefaultDescription
childrenReactNode—The page, rendered untouched inside a centered container.
insetboolean | "dashboard"—Opt into page gutters; "dashboard" preserves the app's content gutters.
testIDstring—data-testid on web.

SidebarDrawerOpener

PropTypeDefaultDescription
labelstring—Accessible name ("Open navigation"), translated by the app.
testIDstring—data-testid on web.