# ResizablePanels

Panels side by side or stacked, with a line between two panels that the user drags or moves with the arrow keys to give one more room, such as a list next to its detail or a query over its results. Sizes are percents of the group.

**Dependencies:** npm: 1 direct, 2 total; registry: 2 direct, 2 total.

## Usage

### When to use

- Let someone give more room to one of two or three panels, such as a list next to its detail.
- Split an editor and its output, or a table and a preview, at a size the user picks.

### When not to use

- The app's main navigation column. Use Sidebar.
- Content that overflows one box. Use ScrollArea.
- Switch between views in one place. Use Tabs.

## Variants

### orientation

Set on ResizablePanelGroup. horizontal puts the panels side by side, vertical stacks them.

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

## Examples

### List and detail

```tsx
<ResizablePanelGroup className="h-64 w-full rounded-container border border-border">
  <ResizablePanel defaultSize={35} minSize={20} className="p-md">
    <p className="text-sm text-text-secondary">Inbox</p>
  </ResizablePanel>
  <ResizableHandle label="Resize inbox" />
  <ResizablePanel className="p-md">
    <p className="text-sm text-text-secondary">Message</p>
  </ResizablePanel>
</ResizablePanelGroup>
```

### Stacked, with a grip

A vertical group puts the panels one over the other; the grip shows where to grab.

```tsx
<ResizablePanelGroup orientation="vertical" className="h-72 w-full rounded-container border border-border">
  <ResizablePanel defaultSize={60} className="p-md">
    <p className="text-sm text-text-secondary">Query</p>
  </ResizablePanel>
  <ResizableHandle label="Resize output" withHandle />
  <ResizablePanel className="p-md">
    <p className="text-sm text-text-secondary">Output</p>
  </ResizablePanel>
</ResizablePanelGroup>
```

### Three panels

```tsx
<ResizablePanelGroup className="h-64 w-full rounded-container border border-border">
  <ResizablePanel defaultSize={25} minSize={15} className="p-md">
    <p className="text-sm text-text-secondary">Folders</p>
  </ResizablePanel>
  <ResizableHandle label="Resize folders" />
  <ResizablePanel className="p-md">
    <p className="text-sm text-text-secondary">Files</p>
  </ResizablePanel>
  <ResizableHandle label="Resize files" />
  <ResizablePanel defaultSize={30} minSize={20} className="p-md">
    <p className="text-sm text-text-secondary">Preview</p>
  </ResizablePanel>
</ResizablePanelGroup>
```

## Do and don't

### Do

- Set minSize so no panel shrinks below what its content needs.
- Save the layout from onLayout and pass it back as defaultSize on the next visit.
- Below md, stack the content or show one panel at a time instead.

### Don't

- Do not use for the app's main navigation column. Use Sidebar, which collapses.
- Do not put more than three panels in one group.
- Do not put a handle at the start or the end; a handle sits between two panels.

## Props

| Name | Type | Values | Default | Description |
| --- | --- | --- | --- | --- |
| `orientation` | `enum` | `horizontal`, `vertical` | `horizontal` | Set on ResizablePanelGroup. horizontal puts the panels side by side, vertical stacks them. |
| `onLayout` | `(sizes: number[]) => void` |  |  | Set on ResizablePanelGroup. Called with every panel's size in percent after a drag or a key press, to save the layout. |
| `keyboardStep` | `number` |  | `5` | Set on ResizablePanelGroup. Percent a handle moves for each arrow key press. |
| `defaultSize` | `number` |  |  | Set on ResizablePanel. Starting size in percent. Panels without one share what is left. |
| `minSize` | `number` |  | `10` | Set on ResizablePanel. Smallest size in percent. |
| `maxSize` | `number` |  | `90` | Set on ResizablePanel. Largest size in percent. |
| `label` (required) | `string` |  |  | Set on ResizableHandle. Names the handle, such as Resize sidebar. |
| `withHandle` | `boolean` |  | `false` | Set on ResizableHandle. Shows a small grip tile on the line, for a handle that is hard to find. |

### Slots

| Name | Required | Description |
| --- | --- | --- |
| `panels` | no | Children of ResizablePanelGroup: ResizablePanel and ResizableHandle, a handle between each two panels, as direct children. |

## Anatomy

| Part | Description |
| --- | --- |
| `root` | The group: a flex row or column that fills its container. Give it a height when it is horizontal. |
| `panel` | One panel. It grows by its share and scrolls on its own when the content is larger. |
| `handle` | The 1px line between two panels, focusable and draggable. |
| `hitArea` | The transparent ::before across the line, size-target-min wide. |
| `grip` | The optional small tile on the line that shows where to grab. |
| `icon` | The grip icon in the tile, 16px. |

## Accessibility

Role: `separator`

| Keys | Action |
| --- | --- |
| `Tab` | Moves focus to the next handle. |
| `ArrowLeft / ArrowRight` | In a horizontal group, makes the panel before the handle smaller or larger by keyboardStep percent. |
| `ArrowUp / ArrowDown` | In a vertical group, makes the panel above the handle smaller or larger by keyboardStep percent. |
| `Home / End` | Makes the panel before the handle as small or as large as its limits allow. |

- Each handle is a focusable separator named by label, such as EN `Resize sidebar`. It controls the panel before it (aria-controls).
- aria-valuenow is the size of the panel before the handle in percent; aria-valuemin and aria-valuemax are its limits, given the next panel's limits too.
- A horizontal group has vertical separators (aria-orientation="vertical") and the reverse.
- In a right-to-left page the arrow keys and the drag follow the reading direction.
- The 1px line has a hit area of size-target-min across it, so it is easy to grab with a finger.

## Install

```bash
npx werewolf-ui add resizable-panels
```

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://www.werewolf-ui.dev/docs/installation.md) for requirements and the alternative registry setup.
