react-resizable-panels: Full Code Guide (2026)
Complete react-resizable-panels guide with copy-paste code: PanelGroup, drag handles, collapse, localStorage persistence and TypeScript types. Fix common errors fast.
react-resizable-panels: PanelOnCollapse, Drag Handles & Examples (2026)
Quick answer. react-resizable-panels is the standard React library for building resizable, draggable layouts. It provides three components โ PanelGroup (the container), Panel (each resizable region), and PanelResizeHandle (the drag handle) โ plus an onCollapse/onExpand API and built-in localStorage persistence so panel sizes survive reloads. It is SSR-safe and works cleanly in Next.js.
What is react-resizable-panels?
react-resizable-panels is the 2026 standard React library for resizable layouts. It provides three components: <PanelGroup> (container), <Panel> (each resizable region), and <PanelResizeHandle> (drag handle between panels). Layout sizes persist to localStorage via the autoSaveId prop. Authored by Brian Vaughn (React DevTools author), 12 kB gzipped, supports React 18 and 19.
npm install react-resizable-panels
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
<PanelGroup direction="horizontal" autoSaveId="example">
<Panel defaultSize={25} minSize={15}><Sidebar /></Panel>
<PanelResizeHandle />
<Panel defaultSize={75}><MainContent /></Panel>
</PanelGroup>
Official package: npmjs.com/package/react-resizable-panels.
TL;DR.
react-resizable-panels(npm package by Brian Vaughn, author of React DevTools) is the 2026 standard for resizable layouts in React. The three core types you need:<PanelGroup>(the container),<Panel>(each resizable area), and<PanelResizeHandle>(the drag handle between panels). Key callbacks:onCollapse: PanelOnCollapsefires when a panel collapses to its minimum, andonResizefires on every drag. Layout state can be persisted tolocalStoragevia theautoSaveIdprop. Below: working code, TypeScript types forPanelOnCollapse, thePanelResizeHandleAPI, and the patterns the npm docs skip.
Resizable panels are a staple of developer tools, IDE-style interfaces, and data dashboards. Users expect to drag a handle to resize the sidebar, collapse a panel to maximise working space, and have the layout persisted across sessions. react-resizable-panels handles keyboard navigation, accessibility (ARIA live announcements), SSR, and persistence out of the box. The repo is at github.com/bvaughn/react-resizable-panels. This guide covers the working patterns: sidebar + main content, horizontal/vertical splits, collapsible panels, the PanelOnCollapse and onResize callbacks, the PanelResizeHandle API, TypeScript types, and localStorage persistence.
Installation
```bash npm install react-resizable-panels ```
As of May 2026: latest is react-resizable-panels ^3.0.x, supports React 18 and 19. Peer dependency: React โฅ 16.14. SSR-safe.
๐ Looking for a Dev Team That Actually Delivers?
Most agencies sell you a project manager and assign juniors. Viprasol is different โ senior engineers only, direct Slack access, and a 5.0โ Upwork record across 1000+ projects.
- React, Next.js, Node.js, TypeScript โ production-grade stack
- Fixed-price contracts โ no surprise invoices
- Full source code ownership from day one
- 90-day post-launch support included
Basic Example: Horizontal Split
```tsx import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
export function SplitPane() {
return (
Three components, total. direction="horizontal" for side-by-side, "vertical" for stacked. autoSaveId persists the size ratios to localStorage automatically โ same key, same layout next visit.
PanelOnCollapse: TypeScript Type and Usage
The PanelOnCollapse callback fires once when a panel transitions from "visible" to "collapsed" (collapsed = size hits the collapsedSize or zero). Together with PanelOnExpand, it gives you both edges of the collapse state machine.
```ts // The exact exported type from react-resizable-panels export type PanelOnCollapse = () => void; export type PanelOnExpand = () => void; ```
Working example:
```tsx import { useState } from 'react'; import { Panel, PanelGroup, PanelResizeHandle, type ImperativePanelHandle } from 'react-resizable-panels'; import type { PanelOnCollapse, PanelOnExpand } from 'react-resizable-panels';
export function CollapsibleSidebar() { const [collapsed, setCollapsed] = useState(false);
const handleCollapse: PanelOnCollapse = () => setCollapsed(true); const handleExpand: PanelOnExpand = () => setCollapsed(false);
return (
Key props:
collapsibleโ enables the collapse behaviour (without it, panels stop atminSize)collapsedSizeโ the size when collapsed (default 0, set โฅ 1 if you want a "rail" UI)onCollapse: PanelOnCollapseโ fires once at the moment of collapseonExpand: PanelOnExpandโ fires once at the moment of expandonResize: PanelOnResizeโ fires on every drag, signature:(size: number, prevSize: number | undefined) => void
For "export type PanelOnCollapse" searches (devs looking at TypeScript declarations for v1.0.5 and beyond), the type signature is unchanged: a no-argument void function. The collapse event carries no payload โ use onResize for that.

๐ Senior Engineers. No Junior Handoffs. Ever.
You get the senior developer, not a project manager who relays your requirements to someone you never meet. Every Viprasol project has a senior lead from kickoff to launch.
- MVPs in 4โ8 weeks, full platforms in 3โ5 months
- Lighthouse 90+ performance scores standard
- Works across US, UK, AU timezones
- Free 30-min architecture review, no commitment
PanelResizeHandle API
<PanelResizeHandle> is the drag region between two panels. Always required between <Panel> components inside a <PanelGroup> โ without it, panels are static.
```tsx <PanelResizeHandle className="my-handle" hitAreaMargins={{ coarse: 15, fine: 5 }} onDragging={(isDragging) => { /* update cursor / overlay state */ }} /> ```
classNameโ full styling control. Tailwind, CSS modules, anything.hitAreaMarginsโ pixel padding around the visible handle for touch / fine-pointer accessibility.coarsefor touch (default 15),finefor mouse (default 5).onDraggingโ boolean callback firestrueon dragstart,falseon dragend. Useful for overlay state or analytics.disabledโ set to true to lock the handle.
Persistent Layout with localStorage
Pass autoSaveId on the <PanelGroup> to persist size ratios automatically:
```tsx
The library writes react-resizable-panels:ide-layout to localStorage whenever sizes change, and reads it on mount. Different autoSaveId per layout, same autoSaveId across pages = same restored state. The persistence is JSON-serialised arrays of sizes; safe to inspect and edit.
For SSR โ the library handles hydration. The initial render uses defaultSize; the client effect reads localStorage and updates. No flash if your defaults are close to the saved sizes; for pixel-perfect SSR, save the layout to a cookie and inject defaultSize from there.
Imperative Control: Refs for Programmatic Resize/Collapse
```tsx import { useRef } from 'react'; import { Panel, PanelGroup, PanelResizeHandle, type ImperativePanelHandle } from 'react-resizable-panels';
function ControlledExample() {
const sidebarRef = useRef
return ( <> <button onClick={() => sidebarRef.current?.collapse()}>Collapse <button onClick={() => sidebarRef.current?.expand()}>Expand <button onClick={() => sidebarRef.current?.resize(50)}>Resize to 50%
<PanelGroup direction="horizontal">
<Panel ref={sidebarRef} defaultSize={20} collapsible>
<Sidebar />
</Panel>
<PanelResizeHandle />
<Panel><MainContent /></Panel>
</PanelGroup>
</>
); } ```
ImperativePanelHandle methods: collapse(), expand(), resize(size), getSize(), getId(), isCollapsed(), isExpanded(). Use for keyboard shortcuts (Cmd+B to toggle sidebar) or sync with external state.
Working Example: IDE-Style 3-Pane Layout
```tsx import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
export function IDELayout() {
return (
<Panel>
<PanelGroup direction="vertical">
<Panel defaultSize={70} minSize={20}>
<EditorPane />
</Panel>
<PanelResizeHandle className="h-px bg-gray-700 hover:bg-blue-500" />
<Panel defaultSize={30} minSize={10} collapsible>
<TerminalPane />
</Panel>
</PanelGroup>
</Panel>
<PanelResizeHandle className="w-px bg-gray-700 hover:bg-blue-500" />
<Panel defaultSize={20} minSize={15} collapsible>
<PreviewPane />
</Panel>
</PanelGroup>
); } ```
Sidebar + editor / terminal stack + preview โ VS Code in 40 lines. Each region is independently collapsible. autoSaveId="ide" makes the entire layout persistent across reloads.
react-resizable-panels vs Alternatives (2026)
| Library | Maintained | Bundle Size | TS Types | Collapse API | Persistence | Notes |
|---|---|---|---|---|---|---|
| react-resizable-panels | โ Active (Brian Vaughn) | ~12 kB gzip | โ Excellent | โ
onCollapse | โ
Built-in autoSaveId | 2026 recommended pick |
react-split-pane | โ ๏ธ Stale (last 2021) | ~8 kB | Partial | โ | โ | Legacy; do not use |
react-reflex | โ ๏ธ Slow updates | ~14 kB | โ | Manual | Manual | Older API, harder a11y |
allotment (VS Code-derived) | โ Active | ~20 kB | โ | โ | โ | Heavier, more features |
react-grid-layout | โ Active | ~50 kB | โ | โ | โ | For draggable grid, not splits |
Use react-resizable-panels for resizable splits. Use allotment if you need the exact VS Code visual. Use react-grid-layout only if you need a free-form draggable grid (dashboard tiles).
Common Pitfalls
- Forgetting
<PanelResizeHandle>between panels. No handle = static layout. Always exactly one handle between every two panels. collapsiblewithoutcollapsedSize. DefaultcollapsedSizeis 0, which hides the panel entirely. SetcollapsedSize={4}for a "rail" UI that's still visible.- Layout flashes on SSR. Save the sizes to a cookie server-side and pass as
defaultSizeto avoid the post-hydration jump. onCollapsefiring repeatedly. It only fires on the transition, not while collapsed. If you see repeated fires, check that you are not toggling thecollapsibleprop.- Touch devices ignoring small handles. Set
hitAreaMargins={{ coarse: 20 }}to give touch users a bigger drag region. - Stale
autoSaveIdafter refactor. When you change layout shape (number of panels),localStorageentries become stale. Either bumpautoSaveIdor read/clear the old key.
FAQ
What is PanelOnCollapse in react-resizable-panels?
PanelOnCollapse is the TypeScript type of the onCollapse callback on <Panel>. Its signature is () => void โ a no-argument void function that fires once when the panel transitions from "visible" to "collapsed." It works alongside PanelOnExpand, which fires on the reverse transition. Both are exported from the package so you can annotate handlers explicitly.
How do I install react-resizable-panels?
npm install react-resizable-panels. Import Panel, PanelGroup, and PanelResizeHandle. Wrap your layout in <PanelGroup direction="horizontal" | "vertical">. Each resizable region is a <Panel> with a <PanelResizeHandle> between every pair.
What is the type of PanelOnCollapse for react-resizable-panels 1.0.5+?
export type PanelOnCollapse = () => void; โ unchanged from 1.0.5 through 3.x. The collapse event carries no payload. For size-change events, use onResize (PanelOnResize = (size: number, prevSize: number | undefined) => void).
What does PanelResizeHandle do?
It is the draggable region between two panels in a <PanelGroup>. Without it, panels are static. Style it with className, control its hit area with hitAreaMargins, listen for drag start/end with onDragging. Always exactly one between each pair of panels.
How do I persist react-resizable-panels layout to localStorage?
Pass an autoSaveId prop to <PanelGroup>. The library serializes sizes to localStorage under react-resizable-panels:<autoSaveId> and restores on mount. No code required.
Is there a working JavaScript resizable dashboard layout example?
Yes โ for the IDE-style 3-pane dashboard pattern (file explorer + editor + preview), see the working example above. For free-form draggable dashboard tiles, use react-grid-layout instead.
Can I control react-resizable-panels imperatively?
Yes. Pass a ref to <Panel> of type ImperativePanelHandle, then call .collapse(), .expand(), .resize(n), .getSize(), .isCollapsed(), .isExpanded(). Useful for keyboard shortcuts and external state sync.
Partnering With Viprasol
We build production React UIs โ IDE-style developer tools, real-time trading dashboards, multi-tenant SaaS admin panels. When the panel layout has to feel native and persistent across thousands of users, we ship the pixel-perfect version, not the prototype.
โ Talk to our team about React app development.
Continue Learning
- React DnD Kit โ drag-and-drop primitives by the same author
- React Optimistic Updates โ UX patterns for fast UI
- React Accessibility & ARIA โ a11y for custom widgets
- Next.js App Router Caching โ layout state in Next.js
- Web Development Services โ production React engineering
react resizable panels: quick recap
To recap, react resizable panels (the react-resizable-panels library) gives you PanelGroup, Panel, and PanelResizeHandle to build resizable, persistent, SSR-safe layouts in React and Next.js.
Installing react-resizable-panels (npm)
Install the package from npm:
npm install react-resizable-panels
Then import PanelGroup, Panel and PanelResizeHandle. The three primitives compose into any resizable layout โ horizontal split views, IDE-style sidebars, or nested grids.
Using react-resizable-panels with shadcn/ui
The shadcn/ui Resizable component is a thin wrapper around react-resizable-panels โ so if you are building a shadcn sidebar resizable layout or a resizable sidebar in shadcn, you are already using this library under the hood. Add it with the shadcn CLI (the "resizable" component) and you get styled ResizablePanelGroup, ResizablePanel and ResizableHandle that map 1:1 to the primitives above. Use the autoSaveId prop to persist panel sizes across reloads.
react-resizable-panels vs react-resizable
These are different libraries. react-resizable is an older package for making a single box resizable by dragging its edges. react-resizable-panels is purpose-built for multi-panel split layouts (think VS Code), with collapsing, nested groups, keyboard support and size persistence. For dashboard and app layouts, react-resizable-panels is the modern choice.
react-resizable-panels FAQ
How do I install react-resizable-panels? Run npm install react-resizable-panels (or the equivalent yarn/pnpm command), then import PanelGroup, Panel and PanelResizeHandle.
Is react-resizable-panels the same as react-resizable? No โ react-resizable resizes a single element; react-resizable-panels builds full multi-panel split layouts.
How do I build a resizable sidebar with shadcn? Use the shadcn Resizable component (it wraps react-resizable-panels): a ResizablePanelGroup with two ResizablePanels and a ResizableHandle.
How do I persist panel sizes? Set the autoSaveId prop on PanelGroup โ sizes are saved to localStorage and restored on reload.
Building a complex resizable UI and want it done right? See our custom web development services.
External Resources
About the Author
Viprasol Tech Team
Custom Software Development Specialists
The Viprasol Tech team specialises in algorithmic trading software, AI agent systems, and SaaS development. With 1000+ projects delivered across MT4/MT5 EAs, fintech platforms, and production AI systems, the team brings deep technical experience to every engagement.
Need a Modern Web Application?
From landing pages to complex SaaS platforms โ we build it all with Next.js and React.
Free consultation โข No commitment โข Response within 24 hours
Need a custom web application built?
We build React and Next.js web applications with Lighthouse โฅ90 scores, mobile-first design, and full source code ownership. Senior engineers only โ from architecture through deployment.