Skip to content
WANCRAFT

B.127Cards & Containers

Resizable Panels

Split panes with draggable, keyboard-operable dividers, px or % limits, snapping collapsible panels and nested groups.

NewReactTailwindadvanced

Overview

Resizable Panels splits a surface into two or more panes, side by side or stacked, with dividers you drag, double-click or drive from the keyboard. Every panel can have a minimum and maximum size in pixels or percent, and dragging cascades: once a neighbour reaches its minimum, the next one starts to give way. Collapsible panels snap shut when dragged past half their minimum and snap open again, can rest at a collapsed size such as an icon rail, and can be toggled by double-clicking or pressing Enter on a divider, or from inside the panel with the useResizablePanel hook. Dividers are focusable separators with aria-valuenow, min, max and aria-controls; arrows resize, Home and End jump to the limits. Groups nest for IDE-style layouts, drags write straight to the DOM and commit once, and onLayout reports the sizes so you can persist them and pass them back as defaultSizes.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/resizable-panels.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/resizable-panels.json

Method 02 · Copy and paste

  1. 1. No extra dependencies — React and Tailwind CSS only.
  2. 2. Copy the source from the Code tab into components/ui/resizable-panels.tsx.
  3. 3. Import it and adjust props.
Dependencies
None
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { ResizablePanels, type ResizablePanel } from "@/components/ui/resizable-panels";

export function ResizablePanelsExample() {
  const panels: ResizablePanel[] = [
    { id: "sidebar", label: "Sidebar", content: <nav className="p-3">Files</nav>, defaultSize: 25, minSize: "160px", collapsible: true, collapsedSize: "40px" },
    { id: "editor", label: "Editor", content: <main className="p-3">Editor</main>, minSize: "30%" },
  ];

  return (
    <div className="h-80 w-full overflow-hidden rounded-xl border">
      <ResizablePanels
        panels={panels}
        onLayout={(sizes) => console.log(sizes)}
      />
    </div>
  );
}

03Props

PropTypeDefaultDescription
panelsResizablePanel[]—Required. { id, content, label?, defaultSize? (%), minSize?, maxSize?, collapsible?, collapsedSize?, defaultCollapsed?, className? }. Sizes are numbers (%) or "240px" / "30%".
direction"horizontal" | "vertical""horizontal"Side by side or stacked. Nest a vertical group inside a panel for IDE layouts.
defaultSizesnumber[]—Initial sizes in percent, e.g. values saved from onLayout.
onLayout(sizes: number[]) => void—Sizes in percent after every committed change (drag end, keys, collapse).
handle"line" | "grip" | "bar""grip"Divider look; every style keeps a 12px hit area.
keyboardStepnumber5Percent per arrow key press; Shift moves four steps.
collapseDurationnumber220Animation in ms for collapse, expand and keyboard moves. Drags follow the pointer.
accentstring"#FF7448"Divider highlight and focus ring colour.
...propsHTMLAttributes<HTMLDivElement>—Forwarded to the group root (add role="group" with an aria-label to name it).
useResizablePanel()() => { size, collapsed, collapsible, collapse, expand, toggle }—Hook for panel content, e.g. a collapse button in a panel header.

04Features

  • 01Two or more panels, horizontal or vertical, nested to any depth
  • 02Min and max sizes in px or %, re-applied when the group resizes
  • 03Cascading drags: neighbours give way in order once one hits its minimum
  • 04Collapsible panels snap shut past half their minimum, rest at a collapsed size and remember their open size
  • 05Collapse by double-click, Enter on a divider, or from panel content via useResizablePanel()
  • 06Drags write to the DOM and commit once; onLayout + defaultSizes for persistence
motion · tweeninput · draginput · keyboardinput · clickinput · pointer

05Accessibility

  • Dividers are focusable role="separator" elements with aria-orientation, aria-valuenow / aria-valuemin / aria-valuemax (percent) and aria-controls pointing at the panel they size.
  • Arrow keys resize (Shift for larger steps), Home and End jump to the minimum (or collapsed size) and maximum, Enter toggles the adjacent collapsible panel.
  • Each divider is named "Resize <panel label>" and shows a visible focus ring around its hit area.
  • Decorative grips and highlight lines are aria-hidden; prefers-reduced-motion makes collapse and keyboard moves instant.

06Limitations

  • Sizes are stored as percentages, so a pixel-sized panel scales with the group until it reaches a pixel limit.
  • Persistence is left to you: save the onLayout sizes and pass them back as defaultSizes.