Resizable

Accessible resizable panel groups and layouts with keyboard support.

Sidebar
Editor
Console
Installation
$Terminal
npx shadcn@latest add https://sdk-components.thesqd.com/r/resizable.json
Usage
Wrap panels in a ResizablePanelGroup and put a ResizableHandle between each pair.
TSImport
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable";
TSExample
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable";

export function Example() {
  return (
    <ResizablePanelGroup orientation="horizontal" className="h-80 rounded-lg border">
      <ResizablePanel defaultSize="40%">One</ResizablePanel>
      <ResizableHandle withHandle />
      <ResizablePanel defaultSize="60%">Two</ResizablePanel>
    </ResizablePanelGroup>
  );
}
Composition
Anatomy of a resizable layout.
ResizablePanelGroup                (react-resizable-panels Group; orientation="horizontal | vertical")
├── ResizablePanel                  (defaultSize / minSize / maxSize / collapsible)
├── ResizableHandle                 (draggable border between panels)
│   ├── withHandle                  (grip pill that follows the pointer along the border)
│   └── gripSide                    (pin the pill to the side being sized: start | end)
└── ResizablePanel
    └── ResizablePanelGroup         (nest a group inside a panel for split layouts)
Horizontal
Side-by-side panels. Hover the border and the grip appears beside it, wherever your pointer lands.
One
Two
Vertical
Stacked panels with a horizontal border; the grip sits above it and tracks the pointer.
Header
Content
Nested
A vertical group inside a horizontal panel for editor-style split layouts.
Sidebar
Editor
Console
API Reference
Built on react-resizable-panels — every upstream prop passes through.

ResizablePanelGroup

PropTypeDefaultDescription
orientation"horizontal" | "vertical""horizontal"Direction panels are laid out and resized in.
defaultLayoutLayout—Initial layout as a map of panel id → percentage.
onLayoutChange(layout: Layout) => void—Fires while the layout is changing.
onLayoutChanged(layout: Layout) => void—Fires once a resize finishes — persist the layout here.
disabledbooleanfalseDisable resizing for every panel and handle in the group.

ResizablePanel

PropTypeDefaultDescription
defaultSizenumber | string—Initial size. Strings like "40%", "240px", "16rem"; bare numbers are pixels.
minSizenumber | string—Smallest size the panel can be dragged to.
maxSizenumber | string—Largest size the panel can be dragged to.
collapsiblebooleanfalseLet the panel collapse to collapsedSize when dragged below minSize.
onResize(size: PanelSize) => void—Fires with the panel's new size (percentage and pixels).

ResizableHandle

PropTypeDefaultDescription
withHandlebooleanfalseShow a grip pill on hover / drag that tracks the pointer along the border.
gripSide"start" | "end"—Pin the grip to the side of the panel being sized (start = left/top, end = right/bottom) instead of the side the pointer came from, and lift the handle above the panels. Use it whenever one panel is fixed and the other is the one being sized.
disabledbooleanfalseDisable dragging this handle.
disableDoubleClickbooleanfalseStop double-click from resetting the panel to its default size.