react-resizable-panels: PanelOnCollapse + Drag Handles (2026)
react-resizable-panels guide: PanelOnCollapse type, PanelResizeHandle API, working code, localStorage persistence, TypeScript types, common pitfalls.
react-resizable-panels: PanelOnCollapse, Drag Handles & Examples (2026)
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
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.