{"id":13900,"library":"react-resizable-panels","title":"React Resizable Panels","description":"react-resizable-panels provides a robust and accessible solution for building resizable panel groups and layouts in React applications. Currently at version 4.10.0, the library maintains an active development pace with frequent patch and minor releases, reflecting ongoing enhancements and bug fixes. Key differentiators include flexible size constraints supporting various units (pixels, percentages, REMs/EMs, viewport units), improved server-side rendering support for both traditional SSR and React Server Components, and a declarative API complemented by imperative escape hatches via refs. It focuses on smooth user interactions with drag, double-click to reset, and keyboard accessibility for resizing, making it suitable for complex UIs like IDEs or dashboards. The library also supports persistent layouts via `useDefaultLayout` and offers granular control over resize behavior, building on a foundation of performance and robustness by its author.","status":"active","version":"4.10.0","language":"javascript","source_language":"en","source_url":"https://github.com/bvaughn/react-resizable-panels","tags":["javascript","typescript"],"install":[{"cmd":"npm install react-resizable-panels","lang":"bash","label":"npm"},{"cmd":"yarn add react-resizable-panels","lang":"bash","label":"yarn"},{"cmd":"pnpm add react-resizable-panels","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency for React applications.","package":"react","optional":false},{"reason":"Peer dependency for rendering React components to the DOM.","package":"react-dom","optional":false}],"imports":[{"note":"The `PanelGroup` component was renamed to `Group` in v4 to align with ARIA standards.","wrong":"import { PanelGroup } from 'react-resizable-panels';","symbol":"Group","correct":"import { Group } from 'react-resizable-panels';"},{"note":"Used to define individual resizable sections within a `Group`.","symbol":"Panel","correct":"import { Panel } from 'react-resizable-panels';"},{"note":"The `PanelResizeHandle` component was renamed to `Separator` in v4 for better ARIA alignment.","wrong":"import { PanelResizeHandle } from 'react-resizable-panels';","symbol":"Separator","correct":"import { Separator } from 'react-resizable-panels';"},{"note":"Hook for managing and persisting layout state, including automatic migration of legacy layout formats since v4.8.0. It's recommended to debounce calls to storage.setItem.","symbol":"useDefaultLayout","correct":"import { useDefaultLayout } from 'react-resizable-panels';"}],"quickstart":{"code":"import React from 'react';\nimport { Group, Panel, Separator } from 'react-resizable-panels';\n\nfunction MyResizableLayout() {\n  const onLayoutChange = (sizes: number[]) => {\n    // This callback fires frequently during drag. For saving, prefer onLayoutChanged.\n    console.log('Layout changing:', sizes);\n  };\n\n  const onLayoutChanged = (sizes: number[]) => {\n    // This callback fires once after dragging is complete.\n    console.log('Layout changed and settled:', sizes);\n    // You might save `sizes` to localStorage here, e.g.,\n    // localStorage.setItem('my-app-layout', JSON.stringify(sizes));\n  };\n\n  return (\n    <div style={{ height: '500px', display: 'flex', border: '1px solid #ccc' }}>\n      <Group direction=\"horizontal\" onLayoutChange={onLayoutChange} onLayoutChanged={onLayoutChanged}>\n        <Panel defaultSize={20} minSize={10}>\n          <div style={{ padding: '10px', background: '#f0f0f0', height: '100%' }}>\n            Sidebar\n          </div>\n        </Panel>\n        <Separator style={{ background: '#ddd', width: '8px', cursor: 'ew-resize' }} />\n        <Panel defaultSize={60} minSize={30}>\n          <Group direction=\"vertical\">\n            <Panel defaultSize={70} minSize={20}>\n              <div style={{ padding: '10px', background: '#e0e0e0', height: '100%' }}>\n                Main Content (Top)\n              </div>\n            </Panel>\n            <Separator style={{ background: '#ccc', height: '8px', cursor: 'ns-resize' }} />\n            <Panel defaultSize={30} minSize={15}>\n              <div style={{ padding: '10px', background: '#d0d0d0', height: '100%' }}>\n                Main Content (Bottom)\n              </div>\n            </Panel>\n          </Group>\n        </Panel>\n        <Separator style={{ background: '#bbb', width: '8px', cursor: 'ew-resize' }} />\n        <Panel defaultSize={20} minSize={10}>\n          <div style={{ padding: '10px', background: '#c0c0c0', height: '100%' }}>\n            Right Panel\n          </div>\n        </Panel>\n      </Group>\n    </div>\n  );\n}\n\nexport default MyResizableLayout;\n","lang":"typescript","description":"This quickstart demonstrates a nested resizable layout using `Group`, `Panel`, and `Separator` components, showcasing horizontal and vertical orientations and how to handle layout changes."},"warnings":[{"fix":"Update imports from `PanelGroup` to `Group` and `PanelResizeHandle` to `Separator`. Change `direction=\"horizontal\"` or `direction=\"vertical\"` to `orientation=\"horizontal\"` or `orientation=\"vertical\"` respectively.","message":"The `PanelGroup` component was renamed to `Group`, and `PanelResizeHandle` to `Separator` in v4. Applications upgrading from v3 must update import statements and component usage. Additionally, the `direction` prop was renamed to `orientation` on `Group` components.","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"Update CSS selectors and accessibility checks to target `[data-disabled='true']` instead of `[aria-disabled='true']` for `Panel` components.","message":"The `Panel` component's `aria-disabled` attribute was replaced with `data-disabled` in v4.7.6. Any custom CSS or accessibility queries targeting `[aria-disabled='true']` on `Panel` elements will no longer function as expected.","severity":"breaking","affected_versions":">=4.7.6"},{"fix":"Avoid attempting to override these specific CSS properties directly on the `Group` component's `style` prop. Adjust parent container styles or wrap `Group` in another `div` for layout adjustments if necessary.","message":"When using the `style` prop on a `Group` component, certain CSS properties (`display`, `flex-direction`, `flex-wrap`, and `overflow`) cannot be overridden by user-provided styles.","severity":"gotcha","affected_versions":">=4.0.0"},{"fix":"For persistent layout saving or actions that should occur once per resize operation, use the `onLayoutChanged` callback instead, which fires only after the pointer has been released.","message":"The `onLayoutChange` callback fires frequently during pointer events (e.g., while dragging a separator), which can lead to performance issues or excessive state updates if used for saving layouts.","severity":"gotcha","affected_versions":">=4.0.0"},{"fix":"Refer to the official documentation for strategies to minimize SSR layout shift, which often involves pre-calculating pixel sizes or using a loading state.","message":"Server-side rendering (SSR) of panels with percentage-based `defaultSize` props may cause a slight layout shift on initial render.","severity":"gotcha","affected_versions":">=4.0.0"},{"fix":"While `useDefaultLayout` handles migration, review the migration guide from v3 to v4 for API changes (e.g., `onCollapse`/`onExpand` removed, `direction` to `orientation`, `PanelResizeHandle` to `Separator`) if manually managing or debugging layout persistence.","message":"The `useDefaultLayout` hook automatically migrates legacy layout formats to the v4 structure, but developers should be aware of this behavior, especially if manually managing layout persistence.","severity":"gotcha","affected_versions":">=4.8.0"},{"fix":"Upgrade to `react-resizable-panels@4.0.12` or higher, where `useDefaultLayout` now defaults to debouncing `storage.setItem` calls by 150ms. If you require immediate saving for specific scenarios (e.g., unit tests), you can explicitly set `debounceSaveMs: 0` in the `useDefaultLayout` options.","message":"The `useDefaultLayout` hook in versions prior to 4.0.12 did not debounce calls to `storage.setItem`. This could lead to excessive storage writes during rapid resizing.","severity":"gotcha","affected_versions":"<4.0.12"}],"env_vars":null,"search_vec":"'4.10.0':27 'access':12,101 'activ':32 'also':116 'api':78 'applic':23 'author':139 'behavior':128 'bug':45 'build':15,129 'click':96 'complement':79 'complex':108 'compon':74 'constraint':52 'control':125 'current':24 'dashboard':113 'declar':77 'develop':33 'differenti':48 'doubl':95 'double-click':94 'drag':93 'enhanc':43 'escap':82 'fix':46 'flexibl':50 'focus':87 'foundat':132 'frequent':36 'granular':124 'group':18 'hatch':83 'ide':111 'imper':81 'improv':61 'includ':49 'interact':91 'javascript':140 'key':47 'keyboard':100 'layout':20,119 'librari':29,115 'like':110 'maintain':30 'make':104 'minor':39 'offer':123 'ongo':42 'pace':34 'panel':3,7,17 'patch':37 'percentag':57 'perform':134 'persist':118 'pixel':56 'provid':8 'react':1,5,22,72 'react-resizable-panel':4 'ref':85 'reflect':41 'releas':40 'rems/ems':58 'render':65 'reset':98 'resiz':2,6,16,103,127 'robust':10,136 'server':63,73 'server-sid':62 'side':64 'size':51 'smooth':89 'solut':13 'ssr':70 'suitabl':106 'support':53,66,117 'tradit':69 'typescript':141 'ui':109 'unit':55,60 'usedefaultlayout':121 'user':90 'various':54 'version':26 'via':84,120 'viewport':59","created_at":"2026-04-20T01:56:53.676004+00:00","updated_at":"2026-04-20T01:56:53.676004+00:00","problems":[{"fix":"Change `import { PanelGroup } from 'react-resizable-panels';` to `import { Group } from 'react-resizable-panels';`","cause":"Attempting to import or use `PanelGroup` which was renamed to `Group` in v4.","error":"TS2339: Property 'PanelGroup' does not exist on type 'typeof import(\"react-resizable-panels\")'."},{"fix":"Change `import { PanelResizeHandle } from 'react-resizable-panels';` to `import { Separator } from 'react-resizable-panels';`","cause":"Attempting to import or use `PanelResizeHandle` which was renamed to `Separator` in v4.","error":"TS2339: Property 'PanelResizeHandle' does not exist on type 'typeof import(\"react-resizable-panels\")'."},{"fix":"Ensure that `Group` components directly contain `Panel` and `Separator` components, and that `Panel` components contain a single React element as their child content.","cause":"A `Group` or `Panel` component received multiple children where only one was expected, or an incorrect nesting structure was used.","error":"Error: React.Children.only expected to receive a single React element child."},{"fix":"Use the `onLayoutChanged` prop on the `Group` component for saving the layout, as it fires reliably after a resize operation is complete. For automatic persistence, ensure `useDefaultLayout` is configured correctly with an `id` and `storage` mechanism.","cause":"Incorrect usage of `onLayoutChange` instead of `onLayoutChanged` for saving state, or issues with the `defaultLayout` prop or `useDefaultLayout` hook.","error":"Layout does not persist or save correctly after resizing."}],"ecosystem":"npm","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"cli_name":"","cli_version":null,"type":"library","homepage":"https://react-resizable-panels.vercel.app/","github":"https://github.com/bvaughn/react-resizable-panels","docs":null,"changelog":null,"pypi":null,"npm":"https://www.npmjs.com/package/react-resizable-panels","openapi_spec":null,"status_page":null,"smithery":null,"categories":["web-framework"],"base_url":null,"auth_type":null,"provenance":{"verified_status":null,"verified_at":null,"last_verified":"2026-06-17","next_check":"2026-07-18","install_tag":null}}