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
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-durationon the group to retune the easing, or0msto 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.
| Value | Meaning |
|---|---|
200 | Pixels |
"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.
Three Panels
Add a ResizablePanel and ResizableHandle pair for each extra section.
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%.
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.
Grip
Use variant="grip" to add a visible grip when the line alone is hard to find.
Gap
Use variant="gap" for a gutter between panels that are cards of their own.
| Variant | Description |
|---|---|
line | The default hairline; a bar grows from it on hover. |
grip | The hairline plus a raised pill. |
gap | An 8px gutter with a pill that shows on hover. |
Nested
Nest a ResizablePanelGroup inside a ResizablePanel to split in both directions.
Grid
Use ResizableGrid to resize columns and rows together; drag where two gridlines cross to resize both.
Saving the Layout
Use useDefaultLayout and give each panel an id to save the layout to localStorage and restore it on load.
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.
| Key | Action |
|---|---|
| Arrow keys | Resize by 5% |
Home / End | Resize to the minimum or maximum |
Enter | Collapse or expand the panel before the handle, if it can |
F6 | Move 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
| v3 | v4 |
|---|---|
direction="horizontal" | orientation="horizontal" (the default) |
defaultSize={30} | defaultSize="30%" |
<ResizableHandle withHandle /> | <ResizableHandle variant="grip" /> |
autoSaveId="layout" | useDefaultLayout({ id: "layout" }) |
onLayout | onLayoutChange or onLayoutChanged |
ref on a panel | panelRef, typed with usePanelRef() |