Resizable
Accessible resizable panel groups and layouts with keyboard support.
Installation
Install the following dependencies:
Set up the token layer and the StyleX compiler, if you have not already. See
Installation. The handle also needs interop.css for its
hover and drag colour.
Copy and paste the following code into your project.
Update the import paths to match your project setup.
Usage
A group is a flex row or column that fills its parent. Panels split it. A handle between two panels can be dragged, takes focus and responds to the arrow keys.
The group sets width: 100%, height: 100%, display, flex-direction and
overflow inline, and an inline declaration beats any class. Give it a floor or
a cap through xstyle (minHeight, maxWidth) and a fixed size through
style.
Size a panel with defaultSize, minSize and maxSize. A number is pixels, a
bare string is a percentage, and a string with a unit is that unit.
defaultSize={50} is 50 pixels, not half the group. Write "50%" or "50"
for the percentage.
Vertical
Use orientation="vertical" to stack the panels.
Handle
Use the withHandle prop on ResizableHandle to draw a grip on the line.
API reference
Every part wraps the react-resizable-panels
part of the same role and accepts its props: Group, Panel and Separator.
Each part also takes xstyle and className.
ResizablePanelGroup
| Prop | Type | Default |
|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" |
defaultLayout | { [panelId: string]: number } | — |
onLayoutChanged | (layout: Layout, meta: { isUserInteraction: boolean }) => void | — |
disabled | boolean | false |
disableCursor | boolean | false |
groupRef | Ref<GroupImperativeHandle> | — |
id | string | number | — |
onLayoutChanged fires once the pointer is released, so save a layout from that
callback. onLayoutChange fires on every pointer move. The library
sets the cursor from its own hit test for the whole page while a handle is
hovered or dragged; disableCursor turns that off.
ResizablePanel
| Prop | Type | Default |
|---|---|---|
defaultSize | number | string | — |
minSize | number | string | — |
maxSize | number | string | — |
collapsible | boolean | false |
collapsedSize | number | string | 0 |
disabled | boolean | false |
onResize | (size: PanelSize, id, prevSize?: PanelSize) => void | — |
panelRef | Ref<PanelImperativeHandle> | — |
id | string | number | — |
The library renders a panel as two elements: an outer flex item it sizes, and an
inner box that scrolls. className, style and xstyle apply to the inner
box, so a style you pass cannot override the sizing.
A collapsible panel snaps to collapsedSize when it is dragged under its
minSize. panelRef reaches collapse(), expand() and isCollapsed(), so a
toggle button can call them. usePanelRef from react-resizable-panels returns
a ref of the right type.
ResizableHandle
| Prop | Type | Default |
|---|---|---|
withHandle | boolean | false |
disabled | boolean | false |
disableDoubleClick | boolean | false |
Double-clicking a handle resets its panels to their default sizes unless
disableDoubleClick is set. A disabled handle cannot be dragged, but its
panels still move when a neighbour is resized; disable the panel too to pin it.
resizableStyles
The style maps behind the handle, exported so the same line and grip can be put on another element.
| Key | Description |
|---|---|
handle | The line: centring flex box, currentColor fill, focus outline |
handles | One style per group orientation, the 1px width or height |
grip | The flat pill: rounding, page fill and hairline |
grips | One style per group orientation, the pill's long side along the line |
Data attributes
| Attribute | On | Effect |
|---|---|---|
data-slot="resizable-panel-group" | the group | Targets the group from a parent |
data-orientation | the group | The orientation prop |
data-slot="resizable-panel" | a panel's outer box | The flex item the library sizes |
data-slot="resizable-handle" | the separator | Where interop.css keys the hover and drag colour |
data-slot="resizable-handle-grip" | the grip | Targets the pill |
data-separator | the separator | The library writes "inactive", "hover", "active", "focus" or "disabled" |
aria-orientation | the separator | Runs across the group, so "vertical" in a horizontal group |
data-group, data-panel | group and outer box | The library writes them, with the id as the value |
data-disabled | a panel's outer box | The library writes it from disabled |