Skip to content

Headless split-pane comparison

How @rozie-ui/resizable compares to the existing split-pane / resizable-panel libraries across the six frameworks. Like the slider and otp, the resizable splitter has no shared vanilla-JS engine — and like them, the split-pane landscape is overwhelmingly per-framework: every ecosystem grew its own splitter (react-resizable-panels for React, splitpanes for Vue, paneforge for Svelte, angular-split for Angular, @corvu/resizable for Solid) with its own API, its own persistence story, and its own — often partial — accessibility coverage. The one option that is framework-agnostic, Split.js, is a styled DOM engine you wrap per framework yourself, and its last release was four years ago. Rozie authors the behaviour once on top of native Pointer Events and the keyboard, and ships it to all six frameworks as the same idiomatic <Resizable>.

Research snapshot: 2026-06-25. The split-pane landscape moves; treat the library names, versions, and feature columns as of that date. Versions cited are from npm/GitHub at that time.

The libraries at a glance

LibraryFramework(s)Headlessa11y (separator role + keyboard)MaintainedN-panel / persistenceNotes
react-resizable-panels (bvaughn)React✅ unstyledrole="separator" + keyboard resize✅ v4.11 (active)✅ N-panel + autoSaveId localStorage + collapseThe dominant React option. Deep: arbitrary panel trees, conditional panels, imperative API. The model shadcn/ui's Resizable wraps.
allotmentReact⚠️ separator role; keyboard partial✅ v1.20✅ N-panel; snap/collapse; no built-in persistDerived from VS Code's split-view. Pixel-oriented, N-pane.
re-resizableReact❌ resize handles, no separator a11y✅ (high downloads)per-element resize, not a panel groupResizes a single box by its edges/corners — a different primitive than a split pane.
react-split-pane (tomkp)React⚠️⚠️ revived (v3.x)2-pane, nestableThe classic; was long-stale, recently saw renewed releases. Pointer-based dividers.
splitpanes (antoniandre)Vue 3 (+2 legacy)⚠️ class hooks✅ as of v4.1 (focusable splitters, keyboard-step, ARIA)✅ v4.1✅ N-panel; persistence is DIYThe de-facto Vue splitter. Keyboard a11y added in the 4.1 line.
vue-resizableVue⚠️⚠️per-element resizeEdge/corner box resizing, not a panel-group splitter.
paneforgeSvelte 5✅ separator + keyboard support✅ v1.0 (Svelte 5 runes)✅ N-panel + nested + localStorage/cookie persistThe svecosystem splitter; a near-port of the react-resizable-panels model. What shadcn-svelte's Resizable wraps.
svelte-splitpanesSvelte⚠️⚠️⚠️ communityN-panelA community port of the splitpanes API to Svelte.
angular-splitAngular⚠️ styled-ish❌ keyboard a11y is an open gap (#98)✅ v20 (Angular 19+)✅ N-panel; gutter resizeThe main Angular splitter. Keyboard accessibility is acknowledged-missing.
@corvu/resizableSolid✅ unstyled✅ Window-Splitter pattern; arrow + shift-expand✅ v0.2✅ N-panelSolid's accessible primitive; closely follows the WAI-ARIA pattern.
solid-resizable-panelsSolid⚠️⚠️ communityN-panelA second Solid option, modeled on react-resizable-panels.
Split.js / Split-Gridvanilla (agnostic)⚠️ ships CSS❌ no separator/keyboard a11y❌ Split.js v1.6.5 (4y), Split-Grid v1.0.11 (5y, inactive)N-panelThe only framework-agnostic engines — but stale, no a11y, and you write the per-framework wrapper. No maintained web-component splitter exists.
@rozie-ui/resizableReact · Vue · Svelte · Angular · Solid · Lit✅ tokenised, re-skinnablerole="separator" + Arrow/Home/End + live aria-value*✅ v0.1 (new)❌ 2-panel only; persist via r-modelOne .rozie source → six idiomatic packages, same API.

These libraries are good — on its home framework each is a reasonable pick, and Rozie does not claim to out-feature react-resizable-panels on React or splitpanes on Vue. The wedge is consistency, coverage, and an accessibility floor that's the same everywhere: there is no split-pane component that spans all six frameworks with the same API. Even the popular React model (react-resizable-panels) is reproduced framework-by-framework through separate ports (paneforge, solid-resizable-panels). Lit / web components have no maintained splitter at all. Rozie gives all six the same idiomatic <Resizable> from one definition — with the WAI-ARIA window-splitter keyboard pattern wired in on every target, which several incumbents (angular-split, the vanilla engines, re-resizable) still lack.

The honest scope: two panels, one number

Be clear about what @rozie-ui/resizable v1 is — and isn't. The incumbents above are, in most cases, more featureful. react-resizable-panels, paneforge, allotment, splitpanes, and angular-split all model an arbitrary N-panel tree with nested groups, percentage arrays, collapse/expand and snap-to-edge affordances, and (in the React/Svelte case) a built-in persistence layer (autoSaveId → localStorage / cookies). Those are real capabilities Rozie does not ship today.

@rozie-ui/resizable deliberately scopes v1 to two panels and one number. The first panel's percent is size (the sole model: true prop); the second takes the remainder via CSS (flex: 1 1 0). There is no panel array, no measured-pixel state, and no echo guard — which is what keeps it fully controlled and two-way bound on all six frameworks, and is why the Angular output is a clean ControlValueAccessor (a splitter position is a form-controllable value). Nested splitters compose (a Resizable inside a panel), but a single N-panel group is not modeled. The trade is explicit: cross-framework parity, a uniform keyboard/ARIA floor, and zero draft state — in exchange for feature depth. See What Rozie defers.

Native pointer capture, no document listeners

The drag uses Pointer Events with setPointerCapture on the handle, so pointermove / pointerup keep firing on the handle through the entire gesture — even when the cursor races past it — with no document-level mousemove listeners to attach and tear down, and no lost-pointer dead zones. Each move converts the pointer coordinate into a first-panel percent off the container rect and clamps it to [min, max]; the panels are positioned purely by one CSS custom property (--rozie-resizable-size). The result is identical on all six targets, including inside Lit's shadow root (getBoundingClientRect reaches the container there too).

Feature matrix

Cell legend: = documented out-of-the-box · = not supported / not present · ⚠️ = partial / consumer-assembly-required.

CapabilityReact (react-resizable-panels)Vue (splitpanes)Svelte (paneforge)Solid (@corvu/resizable)Angular (angular-split)Lit (none)@rozie-ui/resizable
Pointer-capture drag
Keyboard resize (Arrow/Home/End)✅ (4.1)❌ (#98)
role="separator" + live aria-value*⚠️
Min / max clamp
Horizontal + vertical
Two-way value binding⚠️ callback⚠️ events⚠️ callback⚠️ store/signal⚠️ outputsr-model:size (Angular CVA)
Imperative handle✅ ref API⚠️✅ context⚠️hand-rollapplySize / reset
Custom handle slot⚠️handle slot
Zero-config + re-skinnable⚠️ unstyled⚠️ class hooks⚠️ unstyled⚠️ unstyled⚠️✅ CSS-var tokens + shadcn/Material/Bootstrap bridges
N panels (>2)❌ deferred
Built-in layout persistenceautoSaveId⚠️ DIY✅ localStorage/cookie⚠️⚠️⚠️ via r-model (you persist)
Collapse / snap-to-edge⚠️❌ deferred
One source → all 6 frameworks

Where Rozie wins today

  • One definition, six idiomatic packages — including Lit / web components, which have no maintained split-pane component at all. Where the ecosystem offers a different library per framework, @rozie-ui/resizable is one <Resizable> with the same props, the same resize event, the same two-way size, and the same applySize / reset handle on all six.
  • A uniform keyboard + ARIA floor. Arrow / Home / End resizing on a role="separator" with live aria-value* ships on every target. That matters because the floor is uneven in the incumbents: angular-split has no keyboard a11y, the vanilla engines (Split.js / Split-Grid) ship none, re-resizable exposes no separator semantics, and splitpanes only gained keyboard support in its 4.1 line. Rozie's accessibility doesn't depend on which framework you picked.
  • A real two-way size on all sixr-model:size reads and writes the split with no onChange → setState glue, and because size is the sole model: true prop the Angular output is a ControlValueAccessor, so [formControl] / [(ngModel)] bind directly. The per-framework incumbents each expose a different binding shape (React callbacks, Vue events, Svelte stores, Solid signals, Angular outputs).
  • Zero-config styling that re-skins to any design system. Every rendered value is a --rozie-resizable-* CSS custom property, plus ready-made token bridges for shadcn/ui, Material 3, and Bootstrap 5 — where most incumbents ship unstyled and leave the skin to you.

When a competitor is the better pick

This page would not be credible without saying so plainly:

  • You're React-only and need N-panel layouts, persisted across reloads, with collapse/expand. Use react-resizable-panels. It is the mature, dominant option, treats accessibility and persistence as first-class, and is what shadcn/ui's Resizable is built on. Rozie's 2-panel scope simply doesn't cover that shape.
  • You're a VS-Code-style IDE layout in React. allotment is derived from VS Code's own split-view and is purpose-built for that.
  • You're Svelte-only and want the react-resizable-panels feature set natively. paneforge (Svelte 5 runes, nested groups, persistence) is the idiomatic choice.
  • You just need to resize one box by its edges, not split a pane — that's re-resizable, a different primitive entirely.

@rozie-ui/resizable is the right pick when you're building (or maintaining) a component library or design system that must ship the same accessible two-panel splitter across more than one of React, Vue, Svelte, Angular, Solid, and Lit — and you don't want to adopt, learn, and re-test a different library, with a different API and uneven a11y, per framework.

What Rozie defers

This page concedes where the incumbents are genuinely ahead — that's what keeps the comparison credible, and it doubles as Rozie's own roadmap.

  • N-panel layouts. react-resizable-panels, splitpanes, paneforge, allotment, and angular-split model an arbitrary tree of panels with a percentage array and nested groups. @rozie-ui/resizable v1 is deliberately two panels and one size number — which is what keeps it fully controlled with no draft state. Nested splitters can be composed (a Resizable inside a panel) but a single N-panel group is not modeled.
  • Built-in layout persistence. The React (autoSaveId → localStorage) and Svelte (paneforge, localStorage/cookies) incumbents ship a persistence layer. Rozie exposes the position as a two-way size, so persisting it is a one-liner on the consumer side — but there is no built-in storage adapter.
  • Collapse / snap-to-edge affordances. Collapsible panels, snap points, and double-click-to-reset are incumbent features (react-resizable-panels, paneforge, allotment, angular-split) that Rozie does not model today.
  • @rozie-ui/resizable is 0.1.0. The surface (5 props / 1 event / 2-verb handle / 3 slots) is stable and gate-verified across all six targets, but it is younger and less battle-tested than the established per-framework libraries.

Try it

The @rozie-ui/resizable showcase documents the @rozie-ui/resizable-* packages — one pre-compiled, per-framework install. There is no engine to import and no required CSS — the native-pointer behaviour and a fully-tokenised skin ship inside the component, with optional one-line theme bridges for shadcn/ui, Material 3, and Bootstrap 5. The live demo runs the real Vue package in the page.

Cross-references

Pre-v1.0 — internal monorepo.