@magic-spells / split-panel

Split the view.

Draggable, keyboard-accessible resizable panels — horizontal or vertical, nested to any depth, with min/max constraints and layouts that remember themselves.

Install npm i @magic-spells/split-panel
Size 3.7 kB min+gzip · 0 deps

Basic split

Two panels with authored starting sizes. size takes a percent (30 or 30%) or a pixel value (250px). The divider between them is generated automatically. Drag it, or focus it and use the arrow keys (Shift for bigger steps, Enter or double-click to reset).

Panel 1 · size="30%"

Thirty percent to start.

Panel 2 · size="70%"

Seventy percent to start.

Authored dividers

Dividers are generated where you leave them out — but you can also write a <split-divider> between two panels and the group will adopt it, wiring the same drag, keyboard, and ARIA behaviour onto your element instead of replacing it. That is what lets a template or framework own the markup. Here the first divider is authored, the second is generated, and the third is authored with disabled — its handle is hidden and it does not drag.

One

Authored divider →

Two

Generated divider →

Three

Authored, disabled →

Four

Runtime panels

The group watches its own child list, so panels added, removed, or reordered after mount are re-scanned and re-wired on the next microtask. Sizes renormalize to 100 while every panel that stayed keeps the size it was committed to.

A

B

Vertical stack

direction="vertical" stacks panels into rows — the divider becomes horizontal and drags up and down. Panels without a size split the space equally.

Top

Bottom

Nested layouts

A panel can contain another group. Here the right column holds a direction="vertical" group — each group only manages its own direct children, so the dividers never interfere with each other.

Sidebar

One column on the left.

Editor

The right column is its own vertical group.

Console

Min & max limits

Constraints accept pixels or percentages. The sidebar is clamped between min="200px" and max="50%", and the inspector never shrinks below min="15%" — dividers hard-stop at the limits, and the pixel minimum holds even when the window shrinks.

Sidebar · 200px–50%

Main

Inspector · min 15%

Fade to hidden

The left panel starts at size="250px" (its max) and exposes --split-panel-visible — a 1→0 readout of where it sits in its min="0px" max="250px" range, driving the scale/blur/fade. With snap="0 100" and an eased transition, releasing the drag settles it to fully hidden or fully open — whichever is nearer.

Fading

Drag, then release.

Cover

Saved positions

Give a group an id and it persists its sizes to localStorage on every committed change. Drag a divider, reload the page — the layout comes back.

Remembered

Stored under split-panel:demo-layout.

Also remembered

Events & API

Dragging fires a light split-panel:resize stream and a single split-panel:resize-end per gesture. The group also exposes setSizes(), resetSizes(), and a disabled lock. This group has an eased transition, so the setSizes() buttons glide.

A

B