# Resizable

> Columns or rows whose split people drag, with the drag handle sitting on the seam between them.

Source: https://raft-design.botiverse.build/components/resizable. Generated from the current release; where it differs from what you remember, this page is right.

Resizable lets people drag the boundary between two regions to change how much room each one gets: the sidebar and the main area, or a conversation and its thread. The seam between the two columns is the only line, and the drag handle sits on it ([Composites](https://raft-design.botiverse.build/patterns/composites.md#resizable-columns)).

```tsx
import { PanelLeftClose, PanelLeftOpen } from "lucide-react";
import type { ReactNode } from "react";
import {
  AppShellMainSlot,
  AppShellRailSlot,
  AppShellRoot,
  AppShellSidebarSlot,
  AppShellSidebarTrigger,
  ResizableGroup,
  ResizableHandle,
  ResizablePanel,
} from "@botiverse/raft-ui";
import { cn } from "@botiverse/raft-ui/cn";

function ShellRegion({ children, className }: { children: ReactNode; className: string }) {
  return (
    <div
      className={cn(
        "flex size-full min-h-0  min-w-0 items-center justify-center px-2 text-center font-mono text-xs font-semibold uppercase tracking-wide",
        className,
      )}
    >
      {children}
    </div>
  );
}

function SidebarTrigger() {
  return (
    <AppShellSidebarTrigger>
      <PanelLeftClose className="group-data-[state=collapsed]/app-shell-sidebar-trigger:hidden" />
      <PanelLeftOpen className="hidden group-data-[state=collapsed]/app-shell-sidebar-trigger:block" />
    </AppShellSidebarTrigger>
  );
}

export function AppShellCollapsibleSidebarComposition() {
  return (
    <div className="w-full overflow-x-auto">
      <AppShellRoot sidebarCollapsible className="h-[420px] min-w-[860px]">
        <AppShellRailSlot className="flex md:flex">
          <ShellRegion className="w-16 bg-brand-300 text-brand-950">Rail</ShellRegion>
        </AppShellRailSlot>

        <ResizableGroup orientation="horizontal" className="h-full min-w-0 flex-1">
          <ResizablePanel
            id="app-shell-collapsible-sidebar"
            defaultSize={252}
            minSize={180}
            maxSize={368}
            groupResizeBehavior="preserve-pixel-size"
            className="relative min-w-0"
          >
            <AppShellSidebarSlot className="relative flex h-full w-auto min-w-0 flex-1">
              <ShellRegion className="bg-attention-200 text-attention-950">Sidebar</ShellRegion>
            </AppShellSidebarSlot>
          </ResizablePanel>

          <ResizableHandle />

          <ResizablePanel
            id="app-shell-collapsible-main"
            minSize={360}
            className="relative overflow-visible!"
          >
            <AppShellMainSlot className="flex h-full min-w-0 flex-1">
              <div className="flex size-full  flex-col bg-brand-100 text-brand-950">
                <header className="flex h-12 shrink-0 items-center gap-3 border-b border-line-strong px-3">
                  <SidebarTrigger />
                  <span className="font-mono text-xs font-semibold uppercase tracking-wide">
                    Main
                  </span>
                </header>
                <ShellRegion className="flex-1">
                  Click the control to collapse the sidebar
                </ShellRegion>
              </div>
            </AppShellMainSlot>
          </ResizablePanel>
        </ResizableGroup>
      </AppShellRoot>
    </div>
  );
}
```

## When to use

| Situation                                               | Use                                                                 |
| ------------------------------------------------------- | ------------------------------------------------------------------- |
| A split people adjust: the sidebar, the thread panel    | Resizable                                                           |
| Widths fixed by the design                              | The slots of [AppShell](https://raft-design.botiverse.build/components/app-shell.md), or plain layout |
| A side panel that opens and closes beside the main area | A [Panel](https://raft-design.botiverse.build/components/panel.md) in the shell                           |
| Details that cover the page for a while                 | [Drawer](https://raft-design.botiverse.build/components/drawer.md)                                       |

## Anatomy

- `ResizableGroup`: the container. `orientation="horizontal"` (the default) puts its panels side by side; `orientation="vertical"` stacks them. Required.
- `ResizablePanel`: one region, with its default, minimum and maximum size. At least 2.
- `ResizableHandle`: the drag handle between two panels. Required between every adjacent pair: a group without handles is plain layout.

The panels draw no surface, edge or padding. The region inside each panel draws its own, including the one seam between the two ([Page structure](https://raft-design.botiverse.build/patterns/page-structure.md#one-line-between-two-regions)).

## States

| State           | Look                                                             |
| --------------- | ---------------------------------------------------------------- |
| At rest         | Nothing: the seam drawn by the region shows where the handle is  |
| Hover, dragging | A 1px `foreground-muted` line over the seam, and a resize cursor |
| Keyboard focus  | A 2px `foreground` line over the seam                            |

## Behavior

- The handle is 12px wide and centered on the boundary, overlapping each panel by 6px, so it takes no room from either.
- Use the widths in [Spacing](https://raft-design.botiverse.build/foundations/spacing.md#layout-widths) for the default, minimum and maximum: the sidebar and the thread panel each have their own range.
- Pass `groupResizeBehavior="preserve-pixel-size"` on the sidebar's panel, so the sidebar keeps its width when the window changes and the main area takes up the difference.
- Below 768px there are no side-by-side columns to resize ([Responsive layout](https://raft-design.botiverse.build/patterns/responsive.md)).

## Accessibility

- Resizable wraps react-resizable-panels. Each `ResizableHandle` is a focusable `separator` with `aria-valuenow`, `aria-valuemin`, `aria-valuemax` and `aria-controls`.
- Keyboard: the arrow keys along the group's orientation resize in small steps, Home and End go to the minimum and the maximum, Enter collapses or restores a collapsible panel, and F6 moves to the next handle.
- Give every handle an `aria-label` that says what it resizes: "Resize sidebar".

## Rules

- Use Resizable only for splits people adjust. Don't wrap fixed layouts in a group in case they might be resized later.
- Don't draw a line on the handle or a second edge on the panels: the seam of the region is the only line.

## API

### ResizableGroup

Also takes the attributes of its element.

### ResizableHandle

Also takes the attributes of its element.

### ResizablePanel

Also takes the attributes of its element.

## Changes

- 0.0.21 (Added): Added generic `ResizableGroup`, `ResizableHandle`, and `ResizablePanel` primitives for resizable panel layouts.
