react-sortable-pane: a draggable, resizable pane set for React
:sparkles: A sortable and resizable pane component for React.
At a glance
- What is it?
- react-sortable-pane is a small React component library that renders a set of panes you can reorder by dragging and resize by pulling their edges, in controlled or uncontrolled form. It is MIT licensed and the package version is 1.0.4, but the toolchain it was built with is old enough to raise questions about React 18 and 19.
- Who is it for?
- react-sortable-pane suits a React application that needs a dashboard style set of resizable and reorderable panels and does not want to hand-roll drag handling, and the controlled mode with onOrderChange and onResizeStop gives you the hooks to persist a layout.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 170 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two panes, one drag to reorder and one edge to resize
react-sortable-pane is a React component library whose whole job is a set of panes that the user can rearrange. The README calls it a sortable and resizable pane component, and the project description is a sortable and resizable pane component for React.
The split into two components is the API shape. SortablePane is the container, and Pane is an individual child. The container is told a direction, horizontal by default or vertical, and the panes inside it can be dragged to change their order and pulled at the edges to change their size.
The resizing is not built from scratch. The dependency list in package.json includes re-resizable at version 4.7.1, which is the library that handles the drag-to-resize interaction, so react-sortable-pane layers ordering and the pane container on top of an existing resize primitive. The other runtime dependencies tell the rest of the story: react-motion at 0.5.2 for the animation when a pane changes position, lodash.debounce and lodash.isequal for throttling and for comparing state, resize-observer-polyfill so the component can react to container size changes in browsers that do not support ResizeObserver, and tslib for the TypeScript helper imports.
The package version is 1.0.4, the licence is MIT, and the homepage is a GitHub Pages site at bokuweb.github.io/react-sortable-pane that doubles as the Storybook demo, so you can drag panes in the browser before writing any code. There is also a CodeSandbox for the uncontrolled usage. The repository has no GitHub releases, and the last push was on 2026-05-06.
Uncontrolled mode needs two props, controlled mode needs the rest
The library splits its API by who owns the state, and the README is explicit about which props belong to which side.
In uncontrolled mode you do not control SortablePane state, and you use defaultSize and defaultOrder. The example renders three panes with defaultSize and passes defaultOrder to the container:
import * as React from 'react';
import { SortablePane, Pane } from 'react-sortable-pane';
export default function SimpleUncontrolledExample() {
const panes = [0, 1, 2].map(key => (
<Pane key={key} defaultSize={{ width: '100%', height: 120 }}>
00{key}
</Pane>
));
return (
<div>
<SortablePane direction="vertical" margin={20} defaultOrder={['0', '1', '2']}>
{panes}
</SortablePane>
</div>
);
}Notice that the order is expressed as an array of string keys, not as indices, and the pane order in the DOM is separate from the order array.
In controlled mode you supply size and order, and you handle the change events. The full example shows both callbacks:
<SortablePane
direction="vertical"
margin={20}
order={this.state.order}
onOrderChange={order => {
this.setState({ order });
}}
onResizeStop={(e, key, dir, ref, d) => {
this.setState({
panes: { ...this.state.panes, [key]: { height: this.state.panes[key].height + d.height } },
});
}}
>Two details in that snippet are worth flagging. onResizeStop fires only at the end of a resize, not continuously, so it is the right hook for persisting a layout but the wrong one for a live readout. And the resize delta is delivered as d.height, a relative change, which the example applies to the previous height to compute the new one.
The controlled mode also uses the class component syntax with a typed State object, which tells you the library was written against a React version that predates the hooks default.
The prop surface is small, and the documentation table cuts off mid-row
The props table in the README lists the SortablePaneComponent options, and the entries are worth reading in full because several of them are not self-explanatory.
className takes a string and defaults to undefined. style takes React.CssProperties and defaults to an empty object. direction accepts horizontal or vertical and defaults to horizontal. margin is a number, the margin between Pane components, and defaults to 0.
Then there are the two state props. order is a string array used to control Pane order, and defaultOrder is a string array used to set the default Pane order. Each description points at the other mode: the order entry says that if you do not need to control Pane state you can omit this property, and the defaultOrder entry says that if you need to control Pane state you should use order instead.
isSortable is a boolean defaulting to true, controlling whether panes can be dragged at all. disableEffect is a boolean defaulting to false.
That last entry is where the documentation runs out. The table is cut off mid-row at the disableEffect description, and the PaneComponent prop table that would follow is not present in the text available. The props the README does not show you are therefore unknown: the shape of the size and defaultSize objects beyond the width and height shown in the examples, the event handler signatures beyond what the controlled example demonstrates, and whatever options disableEffect switches off. The controlled example gives you onOrderChange and onResizeStop, and the props table confirms nothing further.
The library also ships a PaneComponent section in its table of contents, so the full prop list exists upstream. Reading it there is not optional if you are going to rely on disableEffect, because the truncated entry does not say what disabling the effect does.
The dependency tree dates the project to the React 16 era
The dev dependency list is the most useful signal about where this library sits in time, and it is old.
The React version in devDependencies is 16.7.0, with @types/react at 16.4.6 and @types/react-dom at 16.0.6. Storybook is pinned at 3.4.8 with the react, addon-info and addon-storysource addons at the same version. Cypress is 3.0.2, rollup is 0.60.7 with babel, commonjs, node-globals, node-resolve, replace and typescript2 plugins, babel-core is 6.26.3, prettier is 1.13.7, and typescript is 4.7.4.
Those are not mistakes, they are a snapshot. React 16.7 predates hooks, which explains why the controlled example is written as a class component with a typed State rather than as a function component with useState. Storybook 3 predates the current major versions, and Cypress 3 predates component testing as it exists now. The build output paths in package.json reflect the same era, with main pointing at ./lib/react-sortable-pane.es5.js, a module field at ./lib/react-sortable-pane.js and types at ./lib/index.d.ts.
The engines field is even older, asking for npm 3.0.0 or newer and node 6.0.0 or newer.
The practical question is what happens when you install this into a current React application. The package declares react-motion 0.5.2 as a runtime dependency rather than a peer dependency, so it brings its own React 16 era expectations along, and re-resizable 4.7.1 and react-motion 0.5.2 are both packages that predate the current React API surface. The repository configuration shows active upkeep in other areas, with renovate.json for dependency updates, a .prettierrc, a CircleCI config and a .travis.yml, and the CircleCI badge is still in the README. The gap between the tooling era and the maintenance era is the thing to check before you commit.
Testing, deployment scripts and the two ways to consume it
The repository layout shows a project with a real test setup and a slightly untidy deployment history.
The tests are Cypress, configured through cypress.json with a cypress/ directory at the root, and the dev dependency list includes @cypress/webpack-preprocessor at 2.0.1. The .circleci/ directory holds the CI configuration, and .travis.yml is still present from the era when Travis was the default. The .storybook/ directory and the stories/ directory hold the Storybook configuration and the stories that are published to the GitHub Pages demo.
Deployment is handled by two shell scripts at the root, deploy-minor.sh and deploy-patch.sh, which reflects a release flow built around npm publish with a minor or a patch bump. There is no CHANGELOG file in the repository entries, though the README's table of contents lists a Changelog section, and the html/ directory alongside config/ suggests the older html and config folders are still around alongside the TypeScript sources in src/.
For consumers there are two paths. The Storybook instance at bokuweb.github.io/react-sortable-pane is the interactive reference, and the CodeSandbox covers the uncontrolled case, which is the one that needs no state management. The controlled path has to be read from the README example, since the CodeSandbox is labelled for the uncontrolled usage only.
The package is published on npm as react-sortable-pane, and the installation is unremarkable in both ecosystems:
npm i react-sortable-paneyarn add react-sortable-paneThe MIT licence applies, with the LICENSE file at the repository root, and the author field in package.json is bokuweb, matching the bokuweb.github.io pages domain the demo is served from.
Editorial conclusion
react-sortable-pane suits a React application that needs a dashboard style set of resizable and reorderable panels and does not want to hand-roll drag handling, and the controlled mode with onOrderChange and onResizeStop gives you the hooks to persist a layout. It does not suit a project on React 18 or 19 without checking, because the package declares support for React 16.7 and its peer stack predates the concurrent rendering era, and it does not suit a team that needs accessibility guarantees for keyboard-driven reordering, since the documentation does not describe keyboard interaction. Before you adopt it, check the installed React version against the dev dependency on React 16.7.0, and read the disabled effects and isSortable props carefully since the props table in the documentation is cut off mid-row.
Frequently asked questions
How do I install react-sortable-pane?
Run npm i react-sortable-pane, or yarn add react-sortable-pane. The package is published on npm under that name, is MIT licensed and is at version 1.0.4.
What is the difference between the controlled and uncontrolled usage of react-sortable-pane?
In uncontrolled mode you use defaultSize and defaultOrder and let the component own the state. In controlled mode you pass size and order, and you update them from the onOrderChange and onResizeStop callbacks.
Which React version does react-sortable-pane target?
The dev dependencies pin React 16.7.0 with @types/react 16.4.6, and the controlled example is written as a class component. The engines field asks for node 6.0.0 or newer and npm 3.0.0 or newer.
Can I see react-sortable-pane in action before installing it?
Yes. The Storybook demo is published at bokuweb.github.io/react-sortable-pane, and there is a CodeSandbox for the uncontrolled usage. A screenshot recording is also in the repository under screenshot/.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bokuweb-react-sortable-pane)Was this useful?