Skip to content

Resizable

<ResizablePanelGroup> + <ResizablePanel> + <ResizableHandle> give the user a draggable divider between two or more panels. Wraps react-resizable-panels.

import from "@na/ui/components/resizable" ▶ Open in Storybook packages/ui/src/components/resizable.tsx

When to use

  • IDE-style left-rail + main split where the user wants control.
  • Detail-page split (table / inspector) where the inspector width changes per task.
  • Any layout where the user knows the right ratio better than the design.

Don’t use Resizable for: mobile (resizers don’t work on touch), simple two-up grids (TwoColumnLayout), or layouts where one ratio is correct (don’t give the user a knob if there’s only one good answer).

Horizontal split

Sidebar
Main
<ResizablePanelGroup direction="horizontal">
<ResizablePanel defaultSize={30} minSize={20}>Sidebar</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={70} minSize={40}>Main</ResizablePanel>
</ResizablePanelGroup>

Nested

Left
Top
Bottom
<ResizablePanelGroup direction="horizontal">
<ResizablePanel defaultSize={30}>Left</ResizablePanel>
<ResizableHandle />
<ResizablePanel defaultSize={70}>
<ResizablePanelGroup direction="vertical">
<ResizablePanel defaultSize={50}>Top</ResizablePanel>
<ResizableHandle />
<ResizablePanel defaultSize={50}>Bottom</ResizablePanel>
</ResizablePanelGroup>
</ResizablePanel>
</ResizablePanelGroup>

API

ResizablePanelGroup

Prop Type Default Description
direction * "horizontal" | "vertical" Drives where the handle sits.
autoSaveId string When set, the user's preferred sizes persist to localStorage.
onLayout (sizes: number[]) => void Fires on every drag end with the new ratios.

ResizablePanel

Prop Type Default Description
defaultSize number Initial size as a percentage 0–100.
minSize number Smallest the panel can shrink to.
maxSize number Largest the panel can grow to.
collapsible boolean false Allow drag-to-collapse on the handle.

ResizableHandle

Prop Type Default Description
withHandle boolean false Renders the visible drag affordance — recommended.

Design guidelines

✓ Do

  • Set minSize on every panel — the user shouldn't be able to crush content to 0.
  • Use autoSaveId to persist the user's preferred ratio across sessions.
  • Use withHandle on every ResizableHandle. Without it, the user can't see the affordance.

✗ Don't

  • Use Resizable on mobile. The 8px-wide handle is unusable on touch.
  • Resize a panel that contains a CodeMirror editor without onLayout — the editor needs to recalculate.
  • Skip minSize. Resizable + no min = a panel that can collapse into a 0px sliver.

Accessibility

  • The handle is a real <button role="separator"> with aria-orientation and aria-valuenow — keyboard arrow keys resize.
  • Focus ring shows on the handle when keyboard-focused.

▶ Open Resizable stories in Storybook