# ScrollArea

A scrolling region with a thin themed native scrollbar, for panels, menus, side lists and code blocks of fixed height. Native scrolling and the native scrollbar stay; only its color and width are styled (scrollbar-width thin, scrollbar-color). No custom drawn thumb. The page itself keeps the browser scrollbar.

## Usage

### When to use

- Keep a long list, panel or code block inside a fixed or maximum height while the page stays still.
- Give a scrollable region a thin native scrollbar that follows the current theme.

### When not to use

- The whole page should scroll with its content.
- A list is too long to scan and needs search. Use Combobox.

## Variants

### orientation

Which axes scroll.

Values: `vertical`, `horizontal`, `both`. Default: `vertical`.

### type

auto shows the native scrollbar when content overflows; always reserves its space (scrollbar-gutter stable) so content does not shift.

Values: `auto`, `always`. Default: `auto`.

## Examples

### Recent activity

```tsx
<ScrollArea className="h-48 w-64 max-w-full rounded-container border border-border" label="Recent activity">
  <div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 01</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 02</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 03</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 04</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 05</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 06</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 07</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 08</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
  </div>
</ScrollArea>
```

### Horizontal projects

```tsx
<ScrollArea orientation="horizontal" className="h-40 w-64 max-w-full rounded-container border border-border" label="Projects">
  <div className="flex gap-md p-md">
    <Card className="w-40 shrink-0">
      <CardContent>Website</CardContent>
    </Card>
    <Card className="w-40 shrink-0">
      <CardContent>Mobile app</CardContent>
    </Card>
    <Card className="w-40 shrink-0">
      <CardContent>Documentation</CardContent>
    </Card>
  </div>
</ScrollArea>
```

### Both axes

```tsx
<ScrollArea orientation="both" className="h-48 w-64 max-w-full rounded-container border border-border" label="Project updates">
  <div className="w-160">
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 01</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 02</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 03</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 04</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 05</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 06</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 07</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 08</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
  </div>
</ScrollArea>
```

### Reserved scrollbar space

```tsx
<ScrollArea type="always" className="max-h-48 w-64 max-w-full rounded-container border border-border" label="All projects">
  <div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 01</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 02</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 03</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 04</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 05</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 06</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 07</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Project 08</p>
      <p className="text-xs text-text-secondary">Updated workspace notes</p>
    </div>
  </div>
</ScrollArea>
```

## Do and don't

### Do

- Give the root a height or max height.
- Use in DropdownMenu or Combobox lists only if they need a themed bar; they already scroll natively.
- Provide enough content to overflow the chosen axis. Horizontal content needs a width greater than the viewport and must not shrink.

### Don't

- Do not wrap the whole page.
- Do not hide the scrollbar on content that the user must know scrolls without another cue.

## Props

| Name | Type | Values | Default | Description |
| --- | --- | --- | --- | --- |
| `orientation` | `enum` | `vertical`, `horizontal`, `both` | `vertical` | Which axes scroll. |
| `type` | `enum` | `auto`, `always` | `auto` | auto shows the native scrollbar when content overflows; always reserves its space (scrollbar-gutter stable) so content does not shift. |
| `label` | `string` |  |  | Accessible name for the region when the viewport is focusable. |
| `tabIndex` | `number` |  |  | On the viewport: override automatic tab order. By default it takes focus only when it has no visible, enabled focusable children. |
| `onScroll` | `React.UIEventHandler<HTMLDivElement>` |  |  | On the viewport: native scroll event handler. |
| `style` | `React.CSSProperties` |  |  | On the viewport: inline styles for the native scrolling element. Set the outer dimensions with className. |
| `className` | `string` |  |  | On the outer box: supply height, max height, width, borders and corners. The viewport fills this box. |

### Slots

| Name | Required | Description |
| --- | --- | --- |
| `children` | yes | The content that scrolls. |

## Anatomy

| Part | Description |
| --- | --- |
| `root` | Outer box with a fixed or max height. |
| `viewport` | The scrolling element with overflow auto and the styled native scrollbar. |

## Accessibility

Role: `region`

| Keys | Action |
| --- | --- |
| `Tab` | Focuses the viewport when it has no focusable children, so keyboard users can scroll. |
| `Arrow keys / PageUp / PageDown / Home / End` | Native scrolling on the enabled axes of the focused viewport. |

- Native scrolling stays: wheel, touch, momentum and find-in-page work.
- Pass aria-label when the viewport is focusable so the region has a name.
- Under reduced motion no smooth scrolling is added.
- The scrollbar is the browser's own, so it keeps its platform behavior (overlay scrollbars on touch, dragging, clicking the track).

## Install

```bash
npx werewolf-ui add scroll-area
```

Run `npx werewolf-ui init` once in your app before adding components. Init sets up tokens, their CSS import and agent rules. Add installs this component and its dependencies while preserving your theme. See [Installation](https://werewolf-ui.vercel.app/docs/installation.md) for requirements and the alternative registry setup.
