# Sidebar

App shell navigation beside the page: a column of sections and items from the start edge, with a trigger that collapses it to a rail of icons (each named by a Tooltip) or hides it. Below the md breakpoint the same content opens in a Sheet.

## Usage

### When to use

- Top-level navigation that stays beside the page across a whole product.
- A long list of destinations grouped into named sections.

### When not to use

- Switching between views of the same content. Use Tabs.
- A short list of actions anchored to a control. Use DropdownMenu.
- One optional section on a page. Use Accordion.

## Variants

### collapsible

Set on SidebarProvider. icon keeps a rail of icons with Tooltips when collapsed; offcanvas hides the sidebar on desktop entirely; none fixes it open.

Values: `icon`, `offcanvas`, `none`. Default: `icon`.

### side

Set on SidebarProvider. The edge the sidebar sits on; the Sheet opens from the same edge.

Values: `left`, `right`. Default: `left`.

## Examples

### App navigation

```tsx
<SidebarProvider>
  <SidebarTrigger label="Toggle navigation" />
  <Sidebar>
    <SidebarHeader>
      <p className="px-sm font-sans text-md font-medium text-text-primary">Acme</p>
    </SidebarHeader>
    <SidebarContent>
      <SidebarSection label="Workspace">
        <SidebarItem active leadingIcon={<IconHome size={20}/>} href="#">
          Overview
        </SidebarItem>
        <SidebarItem leadingIcon={<IconChartLine size={20}/>} href="#">
          Reports
        </SidebarItem>
      </SidebarSection>
      <SidebarSection label="Account">
        <SidebarItem leadingIcon={<IconSettings size={20}/>} count={2} href="#">
          Settings
        </SidebarItem>
      </SidebarSection>
    </SidebarContent>
    <SidebarFooter>
      <Button variant="secondary" className="w-full">Invite people</Button>
    </SidebarFooter>
  </Sidebar>
</SidebarProvider>
```

### Offcanvas with a trigger

collapsible offcanvas hides the sidebar on desktop; the trigger toggles it and opens the Sheet on a small screen.

```tsx
<SidebarProvider collapsible="offcanvas" defaultCollapsed>
  <SidebarTrigger label="Toggle navigation" />
  <Sidebar>
    <SidebarContent>
      <SidebarSection label="Menu">
        <SidebarItem leadingIcon={<IconLayoutGrid size={20}/>} leadingIconOn={<IconLayoutGridFilled size={20}/>} active>
          Projects
        </SidebarItem>
      </SidebarSection>
    </SidebarContent>
  </Sidebar>
</SidebarProvider>
```

## Do and don't

### Do

- Give every section a label; it names the nav and orients the reader.
- Mark exactly one item active, the page the user is on.
- Keep the footer for identity and account actions, not navigation.

### Don't

- Don't switch between views of the same content; use Tabs.
- Don't put controls other than items inside the content; put them in the header or footer.
- Don't nest a sidebar inside a sidebar.

## Props

| Name | Type | Values | Default | Description |
| --- | --- | --- | --- | --- |
| `collapsed` | `boolean` |  |  | Set on SidebarProvider. The collapsed state, when you control it. Pair it with onCollapsedChange. |
| `defaultCollapsed` | `boolean` |  | `false` | Set on SidebarProvider. Collapsed on first render. |
| `onCollapsedChange` | `function` |  |  | Set on SidebarProvider. Called with the next collapsed state. |
| `collapsible` | `enum` | `icon`, `offcanvas`, `none` | `icon` | Set on SidebarProvider. icon keeps a rail of icons with Tooltips when collapsed; offcanvas hides the sidebar on desktop entirely; none fixes it open. |
| `side` | `enum` | `left`, `right` | `left` | Set on SidebarProvider. The edge the sidebar sits on; the Sheet opens from the same edge. |
| `label` | `string` |  | `Main` | Set on SidebarContent, the name of its navigation landmark; set on SidebarSection, the group's heading and name (hidden on the icon rail). |
| `active` | `boolean` |  | `false` | Set on SidebarItem. The page this item points to: aria-current="page", the muted accent fill with its strong text, and the fill icon weight. |
| `asChild` | `boolean` |  | `false` | Set on SidebarItem. Renders the item as the single child element, typically a router link. |
| `href` | `string` |  |  | Set on SidebarItem. With it the item is a link; without it a button. |
| `count` | `number` |  |  | Set on SidebarItem. A number after the label in a Badge; on the rail it moves into the Tooltip. |
| `leadingIcon` | `node` |  |  | Set on SidebarItem. The Tabler icon before the label, 20px. |
| `leadingIconOn` | `node` |  |  | Set on SidebarItem. The filled-variant icon (Tabler *Filled, e.g. IconHomeFilled) shown on the active item instead of leadingIcon. |
| `disabled` | `boolean` |  | `false` | Set on SidebarItem. The item cannot activate and dims, including links and slotted router links. Disabled items leave the tab order; on the icon rail their Tooltip still opens on hover. |

### Slots

| Name | Required | Description |
| --- | --- | --- |
| `header` | no | SidebarHeader above the scrolling content. |
| `content` | yes | SidebarContent with one or more SidebarSection of SidebarItem. |
| `footer` | no | SidebarFooter pinned at the end. |

## Anatomy

| Part | Description |
| --- | --- |
| `root` | Sidebar: the desktop column, hidden below md, 256px wide, bordered only on the edge that faces the content. On the icon rail it is one square md item wide plus spacing-sm on each side (49px with the border on mouse, 53px on touch), and the header, content and footer pad with spacing-sm. |
| `header` | SidebarHeader: the block above the scrolling content, such as the workspace name. |
| `content` | SidebarContent: the scrolling group of sections, a nav named by its label (default "Main"). |
| `footer` | SidebarFooter: the block pinned at the end, with a Separator above it. |
| `section` | SidebarSection: a group of related items, named by its label, with the items in a list. |
| `label` | The section heading: 12px medium secondary text, hidden on the icon rail. |
| `item` | SidebarItem: one destination, a link with href, a button without one, or any element with asChild. At least the md control height, 14px medium text, a Badge after the label with count. On the icon rail an item with an icon is a square of the md control height. |
| `current` | The active item, the page the user is on: the muted accent fill with its strong text. |
| `currentIcon` | The active item's icon in the accent icon color, at the fill weight. |
| `icon` | The item's leading Tabler icon at 20px; leadingIconOn (the *Filled variant) replaces it on the active item. |
| `trigger` | SidebarTrigger: one ghost icon button that collapses the sidebar on md and up and opens the Sheet below it, named by its label. With collapsible none it shows only below md. |

## Accessibility

Role: `complementary`

| Keys | Action |
| --- | --- |
| `Tab` | Moves from item to item; items are links or buttons in the page order. |
| `Enter, Space` | A button item activates; a link item follows its href. |
| `Escape` | Closes the Sheet the sidebar becomes on a small screen. |

- The root is an aside (complementary). SidebarContent inside it is the one navigation landmark, named by its label (default "Main").
- Each SidebarSection is a group named by its visible label (aria-labelledby), or by aria-label on the icon rail where the label is hidden. Its items are a list.
- The current page's item sets aria-current="page" and its icon switches to the fill weight; the state never relies on color alone.
- On the rail an item with an icon moves its label into a Tooltip and an sr-only span. Items without icons keep visible text. A disabled item stays out of the tab order, and its Tooltip still opens on hover. Mobile sheets always show full labels.
- The Sheet names itself with an sr-only title; the trigger button carries the same name in aria-label.
- Sidebar parts must sit inside a SidebarProvider; without it they throw.

## Install

```bash
npx shadcn add https://werewolf-ui.vercel.app/r/sidebar.json
```

This also adds `styles/werewolf.css`, the tokens every component uses, and any other component it needs. Import that file once in your root CSS, after `@import "tailwindcss"`, with a path relative to that CSS file (from `app/globals.css` it is `@import "../styles/werewolf.css"`).
