Skip to content

Resizable

Split a layout into draggable, resizable panels — horizontal or vertical, with per-panel min and max sizes.

  • stable
  • since v0.1.0
  • 5.0 kB
  • data-display
  • layout
  • splitter

Handles are keyboard-operable separators (role="separator", aria-orientation, arrow keys to resize, Home/End to clamp).

Preview
Open
tsx

Pass direction="vertical" for a top/bottom split — the handle becomes a horizontal bar.

Preview
Open
tsx

Each ResizablePanel accepts minSize and maxSize (in percent) to clamp how far the surrounding handles can drag.

Preview
Open
tsx

Compose horizontal and vertical groups for IDE-style layouts (sidebar + editor + preview).

Preview
Open
tsx
PropTypeDefaultDescription
direction
"horizontal"|"vertical"
horizontal
Layout axis. `horizontal` arranges panels side-by-side; `vertical` stacks them top-to-bottom.
defaultLayout
Layout
Default layout for the Group. ℹ️ This value allows layouts to be remembered between page reloads. ⚠️ Slight layout shift may occur when server-rendering panels with percentage-based default sizes. Refer to the documentation for suggestions on how to minimize the impact of this.
disableCursor
boolean
This library sets custom mouse cursor styles to indicate drag state. Use this prop to disable that behavior for Panels and Separators in this group.
disabled
boolean
Disable resize functionality.
elementRef
Ref<HTMLDivElement | null>
Ref attached to the root `HTMLDivElement`.
groupRef
Ref<GroupImperativeHandle | null>
Exposes the following imperative API: - `getLayout(): Layout` - `setLayout(layout: Layout): void` ℹ️ The `useGroupRef` and `useGroupCallbackRef` hooks are exported for convenience use in TypeScript projects.
onLayoutChange
((layout: Layout) => void)
Called when the Group's layout is changing. ⚠️ For layout changes caused by pointer events, this method is called each time the pointer is moved. For most cases, it is recommended to use the `onLayoutChanged` callback instead.
onLayoutChanged
((layout: Layout) => void)
Called after the Group's layout has been changed. ℹ️ For layout changes caused by pointer events, this method is not called until the pointer has been released. This method is recommended when saving layouts to some storage api.
resizeTargetMinimumSize
{ coarse: number; fine: number; }
Minimum size of the resizable hit target area (either `Separator` or `Panel` edge) This threshold ensures are large enough to avoid mis-clicks. - Coarse inputs (typically a finger on a touchscreen) have reduced accuracy; to ensure accessibility and ease of use, hit targets should be larger to prevent mis-clicks. - Fine inputs (typically a mouse) can be smaller ℹ️ [Apple interface guidelines](https://developer.apple.com/design/human-interface-guidelines/accessibility) suggest `20pt` (`27px`) on desktops and `28pt` (`37px`) for touch devices In practice this seems to be much larger than many of their own applications use though.
  • Each handle is a role="separator" element with the correct aria-orientation for the group direction.
  • Arrow keys resize the surrounding panels; Home / End clamp to the min / max bounds.
  • Pointer and keyboard drags both honour each panel’s minSize and maxSize.
  • The group itself is a <div> — wrap it in a <section> (or pass aria-label) when its purpose is ambiguous.
  • Pass children to ResizableHandle to render a custom grip while keeping the separator semantics.
  • Nest a vertical Resizable inside a horizontal one for IDE-style layouts (sidebar + editor + preview).
  • Pass withHandle to show the grip — a thick rounded line centered on the divider that grows and turns the accent colour while you drag. The divider has an enlarged invisible grab zone, so it’s easy to grab anywhere along the border.
  • Set defaultSize (percent) on each panel so the initial split is predictable across reloads.
  • Pair minSize with a sensible defaultSize so a panel never collapses below readability.