# react-split-pane

> React split-pane component with hooks and TypeScript

Latest version **3.2.0** (published 2026-02-19) · MIT license · 0 weekly downloads

## Install

```sh
npm install react-split-pane
pnpm add react-split-pane
yarn add react-split-pane
bun add react-split-pane
```

## Health

**Score 60/100 (C)** — status: stable.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 3.2.0 |
| Published | 2026-02-19 |
| First published | 2015-06-14 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=20.0.0 |
| Dependencies | 0 |
| Unpacked size | 101.4 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 3391 |
| Author | tomkp |
| Maintainers | tomkp, wuweiweiwu |
| Keywords | react, react-component, split-pane, react-split-pane, typescript, hooks, resizable, panes, layout, accessibility |

## Links

- npm: https://www.npmjs.com/package/react-split-pane
- Repository: https://github.com/tomkp/react-split-pane
- Homepage: https://github.com/tomkp/react-split-pane#readme
- Issues: https://github.com/tomkp/react-split-pane/issues
- npm.io page: https://npm.io/package/react-split-pane

## Alternatives

- [mobx-react](https://npm.io/package/mobx-react.md) — 2.8M weekly downloads
- [rc-tree](https://npm.io/package/rc-tree.md) — 2.6M weekly downloads
- [@react-oauth/google](https://npm.io/package/@react-oauth/google.md) — 1.3M weekly downloads
- [@wagmi/connectors](https://npm.io/package/@wagmi/connectors.md) — 877.0K weekly downloads
- [vee-validate](https://npm.io/package/vee-validate.md) — 836.4K weekly downloads

## Recent versions

- 3.2.0 (latest) — 2026-02-19
- 2.0.3 (next) — 2019-12-23
- 3.1.0 — 2026-02-18
- 3.0.6 — 2026-01-15
- 3.0.5 — 2026-01-12
- 3.0.4 — 2025-12-24
- 3.0.2 — 2025-12-22
- 3.0.1 — 2025-12-22
- 3.0.0 — 2025-12-22
- 0.1.92 — 2020-08-10
- 0.1.91 — 2020-03-23
- 0.1.89 — 2019-11-12
- 0.1.87 — 2019-03-20
- 0.1.86 — 2019-03-20
- 0.1.85 — 2018-12-10
- … 82 more at https://npm.io/package/react-split-pane/versions

## README

# React Split Pane v3

Modern, accessible, TypeScript-first split pane component for React.

[![NPM version](https://img.shields.io/npm/v/react-split-pane.svg?style=flat)](https://www.npmjs.com/package/react-split-pane)
![NPM license](https://img.shields.io/npm/l/react-split-pane.svg?style=flat)
[![NPM downloads](https://img.shields.io/npm/dm/react-split-pane.svg?style=flat)](https://www.npmjs.com/package/react-split-pane)
[![Bundle size](https://img.shields.io/bundlephobia/minzip/react-split-pane)](https://bundlephobia.com/package/react-split-pane)

**[Live Examples](https://tomkp.github.io/react-split-pane)**

## ✨ Features

- 🪝 **Hooks-based** - Built with modern React patterns
- 📘 **TypeScript** - Full type safety out of the box
- ♿ **Accessible** - Keyboard navigation, ARIA attributes, screen reader support
- 📱 **Touch-friendly** - Full mobile/tablet support
- 🎯 **Flexible** - Controlled/uncontrolled modes, nested layouts, 2+ panes
- 🪶 **Lightweight** - < 5KB gzipped
- ⚡ **Performant** - RAF-throttled resize, optimized renders
- 🎨 **Customizable** - Full styling control

## Installation

```bash
npm install react-split-pane

# or
yarn add react-split-pane

# or
pnpm add react-split-pane
```

## Quick Start

```tsx
import { SplitPane, Pane } from 'react-split-pane';

function App() {
  return (
    <SplitPane direction="horizontal">
      <Pane minSize="200px" defaultSize="300px">
        <Sidebar />
      </Pane>
      <Pane>
        <MainContent />
      </Pane>
    </SplitPane>
  );
}
```

> **Note:** SplitPane requires its container to have explicit dimensions. The component uses `width: 100%` and `height: 100%`, so the parent element must have a defined size. For vertical splits, ensure the parent has an explicit height (e.g., `height: 100vh`). See [Container Sizing](#container-sizing) for details.

## Basic Usage

### Horizontal Split (Side-by-Side)

```tsx
<SplitPane direction="horizontal">
  <Pane defaultSize="25%">
    <LeftPanel />
  </Pane>
  <Pane>
    <RightPanel />
  </Pane>
</SplitPane>
```

### Vertical Split (Top-Bottom)

```tsx
<SplitPane direction="vertical">
  <Pane defaultSize="100px">
    <Header />
  </Pane>
  <Pane>
    <Content />
  </Pane>
</SplitPane>
```

### Controlled Mode

```tsx
function App() {
  const [sizes, setSizes] = useState([300, 500]);

  return (
    <SplitPane onResize={setSizes}>
      <Pane size={sizes[0]} minSize="200px">
        <Sidebar />
      </Pane>
      <Pane size={sizes[1]}>
        <Main />
      </Pane>
    </SplitPane>
  );
}
```

### Nested Layouts

```tsx
<SplitPane direction="vertical">
  <Pane defaultSize="60px">
    <Header />
  </Pane>

  <SplitPane direction="horizontal">
    <Pane defaultSize="250px" minSize="150px">
      <Sidebar />
    </Pane>

    <SplitPane direction="vertical">
      <Pane>
        <Editor />
      </Pane>
      <Pane defaultSize="200px">
        <Console />
      </Pane>
    </SplitPane>
  </SplitPane>
</SplitPane>
```

## Advanced Features

### Persistence

The `usePersistence` hook saves and restores pane sizes to localStorage (or sessionStorage):

```tsx
import { usePersistence } from 'react-split-pane/persistence';

function App() {
  const [sizes, setSizes] = usePersistence({ key: 'my-layout' });

  return (
    <SplitPane onResize={setSizes}>
      <Pane size={sizes[0] || 300}>
        <Sidebar />
      </Pane>
      <Pane size={sizes[1]}>
        <Main />
      </Pane>
    </SplitPane>
  );
}
```

#### usePersistence Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `key` | `string` | Required | Storage key for persisting sizes |
| `storage` | `Storage` | `localStorage` | Storage backend (localStorage or sessionStorage) |
| `debounce` | `number` | `300` | Debounce delay in ms before saving |

```tsx
// Use sessionStorage instead of localStorage
const [sizes, setSizes] = usePersistence({
  key: 'my-layout',
  storage: sessionStorage,
  debounce: 500,
});
```

### Snap Points

```tsx
<SplitPane
  snapPoints={[200, 400, 600]}
  snapTolerance={20}
>
  {/* panes */}
</SplitPane>
```

### Custom Divider

```tsx
function CustomDivider(props) {
  return (
    <div {...props} style={{ ...props.style, background: 'blue' }}>
      <GripIcon />
    </div>
  );
}

<SplitPane divider={CustomDivider}>
  {/* panes */}
</SplitPane>
```

## Keyboard Navigation

The divider is fully keyboard accessible:

- **Arrow Keys**: Resize by `step` pixels (default: 10px)
- **Shift + Arrow**: Resize by larger step (default: 50px)
- **Home**: Minimize left/top pane
- **End**: Maximize left/top pane
- **Escape**: Restore pane sizes to initial state
- **Tab**: Navigate between dividers

## API Reference

### SplitPane Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `direction` | `'horizontal' \| 'vertical'` | `'horizontal'` | Layout direction |
| `resizable` | `boolean` | `true` | Whether panes can be resized |
| `snapPoints` | `number[]` | `[]` | Snap points in pixels |
| `snapTolerance` | `number` | `10` | Snap tolerance in pixels |
| `step` | `number` | `10` | Keyboard resize step |
| `onResizeStart` | `(event) => void` | - | Called when resize starts |
| `onResize` | `(sizes, event) => void` | - | Called during resize |
| `onResizeEnd` | `(sizes, event) => void` | - | Called when resize ends |
| `className` | `string` | - | CSS class name |
| `style` | `CSSProperties` | - | Inline styles |
| `divider` | `ComponentType` | - | Custom divider component |
| `dividerClassName` | `string` | - | Divider class name |
| `dividerStyle` | `CSSProperties` | - | Divider inline styles |

### Pane Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `defaultSize` | `string \| number` | `'50%'` | Initial size (uncontrolled) |
| `size` | `string \| number` | - | Controlled size |
| `minSize` | `string \| number` | `0` | Minimum size |
| `maxSize` | `string \| number` | `Infinity` | Maximum size |
| `className` | `string` | - | CSS class name |
| `style` | `CSSProperties` | - | Inline styles |

## Container Sizing

SplitPane uses `width: 100%` and `height: 100%` and measures its container via ResizeObserver. **The parent container must have explicit dimensions** for panes to render correctly.

### Common Issue: Invisible Panes

If your pane content doesn't appear, the most common cause is a missing height on the parent container. This is especially true for vertical splits:

```tsx
// ❌ Won't work - parent has no height
function App() {
  return (
    <div>
      <SplitPane direction="vertical">
        <Pane><div>Top</div></Pane>
        <Pane><div>Bottom</div></Pane>
      </SplitPane>
    </div>
  );
}

// ✅ Works - parent has explicit height
function App() {
  return (
    <div style={{ height: '100vh' }}>
      <SplitPane direction="vertical">
        <Pane><div>Top</div></Pane>
        <Pane><div>Bottom</div></Pane>
      </SplitPane>
    </div>
  );
}
```

### Solutions

1. **Set explicit height on parent** (recommended for most cases):
   ```css
   .container { height: 100vh; }
   ```

2. **Use absolute positioning**:
   ```css
   .container { position: absolute; inset: 0; }
   ```

3. **Use flexbox with flex-grow**:
   ```css
   .parent { display: flex; flex-direction: column; height: 100vh; }
   .container { flex: 1; }
   ```

## Styling

### Default Stylesheet

Import the optional default styles with CSS custom properties:

```tsx
import 'react-split-pane/styles.css';
```

Customize via CSS variables:

```css
.my-split-pane {
  --split-pane-divider-size: 8px;
  --split-pane-divider-color: #e0e0e0;
  --split-pane-divider-color-hover: #b0b0b0;
  --split-pane-focus-color: #2196f3;
}
```

The default styles include dark mode support via `prefers-color-scheme`.

### Basic Styles

```css
.split-pane {
  height: 100vh;
}

.split-pane-divider {
  background: #e0e0e0;
  transition: background 0.2s;
}

.split-pane-divider:hover {
  background: #b0b0b0;
}

.split-pane-divider:focus {
  outline: 2px solid #2196f3;
  outline-offset: -2px;
}
```

### Expanded Hover Area

This classic pattern creates a thin visible divider with a larger grabbable area that reveals on hover:

```css
.split-pane-divider {
  background: #000;
  opacity: 0.2;
  z-index: 1;
  box-sizing: border-box;
  background-clip: padding-box;
}

.split-pane-divider:hover {
  transition: all 0.2s ease;
}

.split-pane-divider.horizontal {
  width: 11px;
  margin: 0 -5px;
  border-left: 5px solid rgba(255, 255, 255, 0);
  border-right: 5px solid rgba(255, 255, 255, 0);
  cursor: col-resize;
}

.split-pane-divider.horizontal:hover {
  border-left: 5px solid rgba(0, 0, 0, 0.5);
  border-right: 5px solid rgba(0, 0, 0, 0.5);
}

.split-pane-divider.vertical {
  height: 11px;
  margin: -5px 0;
  border-top: 5px solid rgba(255, 255, 255, 0);
  border-bottom: 5px solid rgba(255, 255, 255, 0);
  cursor: row-resize;
}

.split-pane-divider.vertical:hover {
  border-top: 5px solid rgba(0, 0, 0, 0.5);
  border-bottom: 5px solid rgba(0, 0, 0, 0.5);
}
```

### Minimal Divider

A subtle single-pixel divider:

```css
.split-pane-divider.horizontal {
  width: 1px;
  margin: 0;
  background: linear-gradient(to right, transparent, #ccc, transparent);
}

.split-pane-divider.vertical {
  height: 1px;
  margin: 0;
  background: linear-gradient(to bottom, transparent, #ccc, transparent);
}
```

## Tailwind CSS & shadcn/ui

React Split Pane works seamlessly with Tailwind CSS and shadcn/ui. See [TAILWIND.md](./TAILWIND.md) for detailed integration examples including custom dividers and CSS variable overrides.

## Migration from v0.1.x or v2.x

See [MIGRATION.md](./MIGRATION.md) for detailed migration guide.

**Quick changes:**

```tsx
// v0.1.x
<SplitPane split="vertical" minSize={50} defaultSize={100}>
  <div>Pane 1</div>
  <div>Pane 2</div>
</SplitPane>

// v3
<SplitPane direction="horizontal">
  <Pane minSize="50px" defaultSize="100px">
    <div>Pane 1</div>
  </Pane>
  <Pane>
    <div>Pane 2</div>
  </Pane>
</SplitPane>
```

## Browser Support

- Chrome/Edge (latest 2 versions)
- Firefox (latest 2 versions)
- Safari (latest 2 versions)
- Mobile browsers (iOS Safari, Chrome Android)

**Note:** IE11 is not supported. Use v0.1.x for IE11 compatibility.

## Contributing

Contributions are welcome! Please see [CONTRIBUTING.md](./CONTRIBUTING.md).

## License

MIT © [tomkp](https://github.com/tomkp)

---
_Source: https://npm.io/package/react-split-pane · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
