Resizable

Adjustable panels with draggable handles for flexible layouts

Composableoriginal, no Base UI counterpart

Resizable splits a layout into panels with draggable handles between them. Use it for split editors, a sidebar beside content, or any pane layout your users should size themselves.

Preview

One
Two

Installation

Usage

Composition

Place a ResizableHandle between each pair of panels.

Features

  • Collapse, expand, resize(), setLayout(), keyboard steps and a double-click reset ease over 320ms; drags track the pointer 1:1.
  • Set --resizable-duration on the group to retune the easing, or 0ms to turn it off. Reduced motion turns it off too.
  • Double-click a handle to reset its panel to its default size.
  • Panels clip content along the resize axis instead of showing a scrollbar, and scroll along the other.
  • Size the group with ordinary classes such as h-64.

Sizes

Size props take a number or a string, and the two mean different things.

ValueMeaning
200Pixels
"30%"Percent of the group
"30"Percent (a string with no unit)
"12rem"Any of px, %, em, rem, vh, vw

defaultSize={50} is 50px wide, not half the group. Write defaultSize="50%" for a percentage.

Examples

Vertical

Set orientation="vertical" on the group to stack panels.

Header
Content

Three Panels

Add a ResizablePanel and ResizableHandle pair for each extra section.

Left
Middle
Right

Min and Max Size

Use minSize and maxSize to clamp a panel; this sidebar stays between 160 and 280px while the main panel keeps at least 40%.

Sidebar160 to 280px
MainAt least 40%

Collapsible

Use collapsible and collapsedSize to let a panel snap shut when dragged past its minSize, and usePanelRef to toggle it from a button. This example sets collapsedThreshold={24} so the snap commits after a short drag.

Inbox

Drag the sidebar past its minimum to collapse it, or use the toggle. Double-click the handle to reset.

Grip

Use variant="grip" to add a visible grip when the line alone is hard to find.

One
Two

Gap

Use variant="gap" for a gutter between panels that are cards of their own.

Inbox
Message
Reply
VariantDescription
lineThe default hairline; a bar grows from it on hover.
gripThe hairline plus a raised pill.
gapAn 8px gutter with a pill that shows on hover.

Nested

Nest a ResizablePanelGroup inside a ResizablePanel to split in both directions.

Sidebar
Header
Content

Grid

Use ResizableGrid to resize columns and rows together; drag where two gridlines cross to resize both.

Files
Editor
Outline
Terminal

Saving the Layout

Use useDefaultLayout and give each panel an id to save the layout to localStorage and restore it on load.

List
DetailResize, then reload the page

The hook reads localStorage while rendering, so it crashes on the server. Pass a no-op storage until hydration and remount the group once the saved layout is readable, as the example does. For no layout shift at all, store the layout in a cookie and read it on the server.

Accessibility

Each handle is a separator in the tab order, with aria-valuenow, aria-valuemin and aria-valuemax.

KeyAction
Arrow keysResize by 5%
Home / EndResize to the minimum or maximum
EnterCollapse or expand the panel before the handle, if it can
F6Move focus to the next handle

Clicking a handle focuses it, so the arrow keys work straight after.

API Reference

Resizable is built on react-resizable-panels v4. All of its props are supported. The documentation below covers custom props, changed behavior, and the props you need most. usePanelRef, useGroupRef, useGridRef, useDefaultLayout and useDefaultGridLayout are re-exported from the same module.

For the complete API, see the react-resizable-panels documentation.

Props

ResizablePanelGroup

Lays out panels and tracks their sizes. Wraps Group, minus its inline height and width, so sizing classes apply.

ResizablePanel

One resizable region. Wraps Panel. className and style apply to the inner container, which clips along the resize axis; pass style={{ overflow: "auto" }} to scroll both ways.

ResizableHandle

Draggable divider between two panels. Wraps Separator.

ResizableGrid

Two-dimensional layout of cells. Wraps Grid, minus its inline height and width.

ResizableCell

One cell of a grid. Wraps Cell and clips its content on both axes; put a scroll container inside a cell that needs one.

ResizableGridline

Draggable line between two columns or two rows. Wraps Gridline, which forwards only className, style, disabled, elementRef and children besides the props below.

Migrating from v3

v3v4
direction="horizontal"orientation="horizontal" (the default)
defaultSize={30}defaultSize="30%"
<ResizableHandle withHandle /><ResizableHandle variant="grip" />
autoSaveId="layout"useDefaultLayout({ id: "layout" })
onLayoutonLayoutChange or onLayoutChanged
ref on a panelpanelRef, typed with usePanelRef()