Decision. Two different needs, two different libraries. For fixed grids-and-forms-side-by-side with draggable dividers, adopt react-resizable-panels — unstyled, zero-dependency, the de-facto standard [1]. For Visual Studio-style panes the user drags, tab-stacks, splits, and floats, adopt Dockview — the one modern, actively-maintained, framework-agnostic docker [2]. You can start with the first and add the second later without ripping anything out.
The four angles converge on one architecture: a splitter for the app shell (regions whose boundaries move but whose contents are fixed) and, only if users need to rearrange the workspace itself, a docking layer on top. These aren’t competitors — they answer different questions. “I want a grid next to a form” is a splitter problem; “I want the user to drag the form into a tab beside the grid, then pop it into its own window” is a docking problem.
The ecosystem has consolidated, but 2026 was a year of breaking majors. Both winners are zero-dependency and TypeScript-first, and both shipped disruptive rewrites the tutorials haven’t caught up to. react-resizable-panels v4 renamed the whole public API (PanelGroup→Group, PanelResizeHandle→Separator, data-*→aria-*) [3] — enough to break shadcn/ui’s Resizable [4]. Dockview v7 split its React bindings into a separate dockview-react package [5], and react-mosaic v7 moved to an n-ary tree with first-class tabs, invalidating the old “mosaic can’t tab-stack” lore [6]. Pin versions and read the changelog, not the blog posts. One rough edge remains: Dockview still has an open StrictMode double-render issue under React 19 [7].
Persistence is the seam that ties the tiers together — and the one that bites. A splitter serializes a trivial size array (autoSaveId + a swappable storage prop) [8]; a docker serializes a panel tree keyed by string component name [9]. That difference is the whole problem: when you remove a panel in a later release, a restored layout references a component that no longer exists and fromJSON throws, wedging the dock [10]. Any docking deployment needs version-stamped layouts, unknown-panel pruning, and a try/catch fallback to a default — non-negotiable, not nice-to-have.
Hosting the actual grids and forms is where naive setups break. A grid only fills a resizing pane if every ancestor in the flex chain has min-height: 0 [11]; let the grid own its resize response (AG Grid flex columns over sizeColumnsToFit on every resize event) [12]. The sharpest trap is docking-specific: Dockview’s default onlyWhenVisible renderer removes hidden panels from the DOM, so switching tabs unmounts your form and loses its state [13] — fix it with renderer: 'always' or by lifting form state out of the pane tree entirely.
So the open question isn’t which library — it’s where user-controlled layout stops paying for itself. Every docking feature you enable (float, popout, tab-stack) multiplies the persistence and unmount edge cases above. Start with fixed splits; add docking only for the screens that genuinely earn it.