<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# Sidebar

The column of links down the side of an app, in sections, with the current page marked `aria-current="page"` and a bar at the start edge, distinct from hover and press highlights. An item can carry a `badge` ("Inbox 12"), be a button (`onClick` without `href`), or hold one level of nested links (`items`). From 640px up it fills its container's height and collapses to a rail of icons with its own button, each named by a `Tooltip`, where an item with nested links opens them in a `Menu`; below 640px it is a menu button that opens the same links as a `Sheet` drawer. Links render through `OuroProvider`'s `linkComponent`, so your router navigates.

```tsx
import { Sidebar } from "@/components/ouro/sidebar/sidebar";
```

## Example

```tsx
<Sidebar
  label="Main"
  header={<Link href="/">Spoonjoy</Link>}
  sections={[
    { items: [{ label: "Recipes", href: "/recipes", icon: <BookIcon /> }] },
    { label: "Library", items: [{ label: "Cookbooks", href: "/cookbooks", icon: <StackIcon /> }] },
  ]}
  currentPath={pathname}
/>
```

## Usage

The phone menu opens once JavaScript has loaded (after hydration); the links are in the server HTML from 640px up.

Put it in a `SidebarLayout`, which places it beside the page and in the phone's top bar.

## Use instead when

- Use `Navbar` instead for a handful of links across the top, and `Tabs` for views of one page.

## Props

Type: `SidebarProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string` |  | Layout only: grid placement and margins (`row-span-2`). Appearance classes warn in development. |
| `closeLabel` | `string` | `"Close"` | The label of the drawer's close button. |
| `collapsed` | `boolean` |  | Whether the sidebar is collapsed, when you control it (to remember it). Pair it with `onCollapsedChange`. |
| `collapseLabel` | `string` | `"Collapse sidebar"` | The collapse button's name and text; `aria-pressed` says whether it is on. |
| `collapsible` | `boolean` | `true` | Whether the sidebar has a button that collapses it to a rail of icons, from 640px up. |
| `currentPath` | `string` |  | The path of the page being shown, from your router (`useLocation().pathname`, or `usePathname()` in Next.js). The link to that path, or else the longest link above it (`/recipes` for `/recipes/12`), gets `aria-current="page"` and the current look. |
| `defaultCollapsed` | `boolean` | `false` | Whether the sidebar starts collapsed, when it keeps its own state. |
| `footer` | `ReactNode` |  | Below the links: the signed-in person, an account `Menu`. Clipped to the rail when collapsed. |
| `header` | `ReactNode` |  | Above the links: your logo, product name or a workspace `Menu`. Clipped to the rail when collapsed. |
| `label` (required) | `string` |  | Names the navigation for screen readers ("Main"). It is not shown. |
| `menuLabel` | `string` | `"Menu"` | Below 640px: the name of the button that opens the sidebar as a drawer, and the drawer's title (shown when there is no `header`). |
| `onCollapsedChange` | `((collapsed: boolean) => void)` |  | Called with the new state when the person collapses or expands the sidebar. |
| `ref` | `Ref<HTMLDivElement>` |  | Reaches the rendered element. |
| `sections` (required) | `readonly SidebarSection[]` |  | The links, in groups: `sections={[{ items: [...] }, { label: "Library", items: [...] }]}`. |

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `children`: Not rendered. The sidebar is `sections`, `header` and `footer`.
- `isCollapsed`: Not a prop. Ouro UI uses `collapsed` with `onCollapsedChange`, or `defaultCollapsed`.
- `items`: Not a prop. Links go in `sections`: `sections={[{ items: [{ label: "Recipes", href: "/recipes" }] }]}`.
- `pathname`: Not a prop. Ouro UI uses `currentPath`: `<Sidebar currentPath={pathname}>`.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`).

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.

## Types

### `SidebarButtonItem`

A button in a Sidebar, for an action rather than a page: "New chat", "Search" opening a `Command`.

```ts
interface SidebarButtonItem extends SidebarItemBase {
  /** What the button does. In the phone's drawer, the drawer closes first. */
  onClick: (event: MouseEvent<HTMLElement>) => void;
  /** Not with `onClick` alone. Give a link `href`; a button has none. */
  href?: never;
  /** Not on a button. Only a link can be the current page. */
  current?: never;
  /** Not on a button. Nested links go in an item without `onClick`: `{ label: "Settings", items: [...] }`. */
  items?: never;
}
```

### `SidebarGroupItem`

An item with links nested under it, one level deep: a button that shows and hides them. It starts open when it holds the current page. On the collapsed rail the button opens them in a `Menu` beside it.

```ts
interface SidebarGroupItem extends SidebarItemBase {
  /** The nested links and buttons. They do not nest further. */
  items: readonly (SidebarLinkItem | SidebarButtonItem)[];
  /** Not with `items`. To link the group's own page, make it the group's first item. */
  href?: never;
  /** Not with `items`; the group's button shows and hides them. */
  onClick?: never;
  /** Not on a group. One of its links is the current page. */
  current?: never;
}
```

### `SidebarItem`

One item of a Sidebar: a link (`href`), a button (`onClick`), or links nested under a button (`items`).

```ts
type SidebarItem = SidebarLinkItem | SidebarButtonItem | SidebarGroupItem;
```

### `SidebarLinkItem`

A link in a Sidebar.

```ts
interface SidebarLinkItem extends SidebarItemBase {
  /** Where it goes. Internal paths go through `OuroProvider`'s `linkComponent` (your router's link). */
  href: string;
  /**
   * Marks this link as the current page (`aria-current="page"`), when the Sidebar's
   * `currentPath` cannot tell: a link whose page lives at another path.
   */
  current?: boolean | undefined;
  /** Called when the link is followed, before your router navigates. */
  onClick?: ((event: MouseEvent<HTMLElement>) => void) | undefined;
  /** Not with `href`. Nested links go in an item without `href`: `{ label: "Settings", items: [...] }`. */
  items?: never;
}
```

### `SidebarSection`

A group of links in a Sidebar, under an optional label.

```ts
interface SidebarSection {
  /** The group's name, shown above its links: "Library". */
  label?: string | undefined;
  /** The group's items, in order: links, buttons and nested links. */
  items: readonly SidebarItem[];
}
```
