---
title: Resizable
description: Adjustable panels separated by draggable handles.
group: Components
order: 55
---

Split a view into panels that resize by drag or keyboard. Built on [react-resizable-panels](https://github.com/bvaughn/react-resizable-panels).

```tsx
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"

export function Example() {
  return (
    <ResizablePanelGroup
      orientation="horizontal"
      className="min-h-[200px] w-full max-w-md rounded-md border border-border"
    >
      <ResizablePanel defaultSize="25%">
        <div className="grid h-full place-items-center">
          <span className="text-sm font-medium tracking-wide text-foreground">
            One
          </span>
        </div>
      </ResizablePanel>
      <ResizableHandle />
      <ResizablePanel defaultSize="75%">
        <ResizablePanelGroup orientation="vertical">
          <ResizablePanel defaultSize="25%">
            <div className="grid h-full place-items-center">
              <span className="text-sm font-medium tracking-wide text-foreground">
                Two
              </span>
            </div>
          </ResizablePanel>
          <ResizableHandle />
          <ResizablePanel defaultSize="75%">
            <div className="grid h-full place-items-center">
              <span className="text-sm font-medium tracking-wide text-foreground">
                Three
              </span>
            </div>
          </ResizablePanel>
        </ResizablePanelGroup>
      </ResizablePanel>
    </ResizablePanelGroup>
  )
}
```

## Installation

```bash
npx @arctis-sh/@arctis-sh/ui@latest add resizable
```

## Usage

```tsx
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"
```

```tsx
<ResizablePanelGroup
  orientation="horizontal"
  className="min-h-[200px] max-w-md rounded-md border border-border"
>
  <ResizablePanel defaultSize="25%">Sidebar</ResizablePanel>
  <ResizableHandle />
  <ResizablePanel defaultSize="75%">Main</ResizablePanel>
</ResizablePanelGroup>
```

## Composition

```tree
ResizablePanelGroup
├── ResizablePanel
├── ResizableHandle
└── ResizablePanel
```

## Basic

Nest groups to combine directions. This example uses a horizontal split with a vertical split on the right.

```tsx
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"

export function Example() {
  return (
    <ResizablePanelGroup
      orientation="horizontal"
      className="min-h-[200px] w-full max-w-md rounded-md border border-border"
    >
      <ResizablePanel defaultSize="25%">
        <div className="grid h-full place-items-center">
          <span className="text-sm font-medium tracking-wide text-foreground">
            One
          </span>
        </div>
      </ResizablePanel>
      <ResizableHandle />
      <ResizablePanel defaultSize="75%">
        <ResizablePanelGroup orientation="vertical">
          <ResizablePanel defaultSize="25%">
            <div className="grid h-full place-items-center">
              <span className="text-sm font-medium tracking-wide text-foreground">
                Two
              </span>
            </div>
          </ResizablePanel>
          <ResizableHandle />
          <ResizablePanel defaultSize="75%">
            <div className="grid h-full place-items-center">
              <span className="text-sm font-medium tracking-wide text-foreground">
                Three
              </span>
            </div>
          </ResizablePanel>
        </ResizablePanelGroup>
      </ResizablePanel>
    </ResizablePanelGroup>
  )
}
```

## Vertical

Use `orientation="vertical"` for stacked panels. Give the group a height, such as `min-h-[200px]`.

```tsx
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"

export function Example() {
  return (
    <ResizablePanelGroup
      orientation="vertical"
      className="min-h-[200px] w-full max-w-md rounded-md border border-border"
    >
      <ResizablePanel defaultSize="25%">
        <div className="grid h-full place-items-center">
          <span className="text-sm font-medium tracking-wide text-foreground">
            Header
          </span>
        </div>
      </ResizablePanel>
      <ResizableHandle />
      <ResizablePanel defaultSize="75%">
        <div className="grid h-full place-items-center">
          <span className="text-sm font-medium tracking-wide text-foreground">
            Content
          </span>
        </div>
      </ResizablePanel>
    </ResizablePanelGroup>
  )
}
```

## Handle

Pass `withHandle` on `ResizableHandle` for a visible grip. The grip rotates automatically in vertical groups.

```tsx
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"

export function Example() {
  return (
    <div className="grid w-full max-w-md gap-6">
      <ResizablePanelGroup
        orientation="horizontal"
        className="min-h-[200px] rounded-md border border-border"
      >
        <ResizablePanel defaultSize="25%">
          <div className="grid h-full place-items-center">
            <span className="text-sm font-medium tracking-wide text-foreground">
              Sidebar
            </span>
          </div>
        </ResizablePanel>
        <ResizableHandle withHandle />
        <ResizablePanel defaultSize="75%">
          <div className="grid h-full place-items-center">
            <span className="text-sm font-medium tracking-wide text-foreground">
              Content
            </span>
          </div>
        </ResizablePanel>
      </ResizablePanelGroup>

      <ResizablePanelGroup
        orientation="vertical"
        className="min-h-[200px] rounded-md border border-border"
      >
        <ResizablePanel defaultSize="35%">
          <div className="grid h-full place-items-center">
            <span className="text-sm font-medium tracking-wide text-foreground">
              Header
            </span>
          </div>
        </ResizablePanel>
        <ResizableHandle withHandle />
        <ResizablePanel defaultSize="65%">
          <div className="grid h-full place-items-center">
            <span className="text-sm font-medium tracking-wide text-foreground">
              Content
            </span>
          </div>
        </ResizablePanel>
      </ResizablePanelGroup>
    </div>
  )
}
```

## Constraints

Use `minSize` and `maxSize` to set resize limits. Percentage strings, including unitless strings like `"50"`, are relative to the group; numbers are pixels.

```tsx
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"

export function Example() {
  return (
    <ResizablePanelGroup
      orientation="horizontal"
      className="min-h-[200px] w-full max-w-md rounded-md border border-border"
    >
      <ResizablePanel
        defaultSize="30%"
        minSize="20%"
        maxSize="50%"
      >
        <div className="grid h-full place-items-center">
          <span className="text-sm font-medium tracking-wide text-foreground">
            20%–50%
          </span>
        </div>
      </ResizablePanel>
      <ResizableHandle withHandle />
      <ResizablePanel minSize="30%">
        <div className="grid h-full place-items-center">
          <span className="text-sm font-medium tracking-wide text-foreground">
            Remaining
          </span>
        </div>
      </ResizablePanel>
    </ResizablePanelGroup>
  )
}
```

## API Reference

### ResizablePanelGroup

| Prop | Type | Default |
| --- | --- | --- |
| orientation | "horizontal" \| "vertical" | "horizontal" |
| resizeTargetMinimumSize | { coarse: number; fine: number } | { coarse: 8, fine: 4 } |
| className | string | — |

```tsx
<ResizablePanelGroup orientation="horizontal">
  <ResizablePanel defaultSize="50%">A</ResizablePanel>
  <ResizableHandle />
  <ResizablePanel defaultSize="50%">B</ResizablePanel>
</ResizablePanelGroup>
```

### ResizablePanel

Size props accept `"25%"`, unitless percentage strings, or pixel numbers.

| Prop | Type | Default |
| --- | --- | --- |
| defaultSize | string \| number | — |
| minSize | string \| number | — |
| maxSize | string \| number | — |
| collapsible | boolean | — |
| collapsedSize | string \| number | 0% |
| disabled | boolean | — |
| className | string | — |

```tsx
<ResizablePanel defaultSize="50%">A</ResizablePanel>
```

### ResizableHandle

| Prop | Type | Default |
| --- | --- | --- |
| withHandle | boolean | — |
| disabled | boolean | — |
| disableDoubleClick | boolean | — |
| className | string | — |

See the [react-resizable-panels docs](https://react-resizable-panels.vercel.app/) for the full primitive API.

```tsx
<ResizableHandle />
```

## Source

```tsx
"use client";

import { Group, Panel, Separator } from "react-resizable-panels";
import type { GroupProps, PanelProps, SeparatorProps } from "react-resizable-panels";
import { cn } from "@/lib/utils";

const resizeTargetMinimumSize = {
  coarse: 8,
  fine: 4,
};

function ResizablePanelGroup({
  className,
  resizeTargetMinimumSize: resizeTargetMinimumSizeProp = resizeTargetMinimumSize,
  ...props
}: GroupProps) {
  return (
    <Group
      data-slot="resizable-panel-group"
      resizeTargetMinimumSize={resizeTargetMinimumSizeProp}
      className={cn(
        "flex h-full w-full ![touch-action:pan-x_pan-y] aria-[orientation=vertical]:flex-col",
        className,
      )}
      {...props}
    />
  );
}

function ResizablePanel({ className, ...props }: PanelProps) {
  return (
    <Panel
      data-slot="resizable-panel"
      className={cn("![touch-action:pan-x_pan-y]", className)}
      {...props}
    />
  );
}

function ResizableHandle({
  withHandle,
  className,
  ...props
}: SeparatorProps & {
  withHandle?: boolean;
}) {
  return (
    <Separator
      data-slot="resizable-handle"
      className={cn(
        "relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90",
        className,
      )}
      {...props}
    >
      {withHandle ? (
        <div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border border-border bg-border">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            fill="currentColor"
            className="size-2.5 text-muted-foreground"
            aria-hidden
          >
            <circle cx="9" cy="5" r="1.5" />
            <circle cx="9" cy="12" r="1.5" />
            <circle cx="9" cy="19" r="1.5" />
            <circle cx="15" cy="5" r="1.5" />
            <circle cx="15" cy="12" r="1.5" />
            <circle cx="15" cy="19" r="1.5" />
          </svg>
        </div>
      ) : null}
    </Separator>
  );
}

export { ResizableHandle, ResizablePanel, ResizablePanelGroup };
```
