A layout component for splitting a space into resizable, nestable panes with draggable handles.
SplitView lays out resizable panes along one axis. Place a SplitViewResizer between two
SplitViewPanes to make that boundary draggable. Nest a SplitView inside a pane for
two-dimensional (columns and rows) layouts.
The group must have a height for the panes to fill — set one on the SplitView (or a parent).
A two-pane split with a draggable boundary. defaultSizes seeds the flexible panes'
percentages; drag the handle to resize.
orientation="vertical" splits into stacked, resizable rows.
Nest a vertical SplitView inside a pane of a horizontal one to get resizable columns and
rows.
A pane's size is interpreted by unit: a percentage ('30', '30%') is a flexible pane that
shares leftover space, while a pixel length (120, '120px', '12rem') is a fixed track
that keeps its width as the container resizes. Set isResizable={false} on a fixed pane and omit
the resizer beside it to keep it static.
Constrain how far a pane can be resized with minSize / maxSize (pixels or percentages).
Set isHidden to collapse a pane to zero and let the remaining panes take its space; the pane
stays mounted and restores its size when shown again. Deciding when to hide (and rendering any
toggle affordance) is up to you.
snaps are percentages the boundary is pinned to. When set, dragging a resizer moves discretely
between these points (snapping to the nearest one) instead of resizing smoothly — useful for
offering a few preset splits.
SplitView is uncontrolled by default. To persist a user's layout, read the sizes from
onResizeEnd (fired once a drag or keyboard change is committed) and store them, then pass them
back as defaultSizes. For full control, pass sizes and update it from onSizesChange.
useStoredSplitViewThe useStoredSplitView hook wires that persistence up for you. Give it an id and spread the
result onto the SplitView — the layout is saved to localStorage on resize and restored on the
next load. Resize the example below and reload the page: it comes back the way you left it.
Custom storage — by default the hook uses localStorage (falling back to a no-op when it's
unavailable, e.g. during server rendering). Pass a storage object ({ getItem, setItem }) to
persist somewhere else — cookies for SSR, or an in-memory stub for tests.
When panels are shown and hidden, give each SplitViewPane a stable id and pass the currently
visible ids as panelIds. Each configuration then remembers its own layout, and the split
re-applies the stored layout for whichever configuration is active — no remounting required.
Resize a boundary, toggle the preview off and on, and the layout comes back.
Each SplitViewResizer is a role="separator" with aria-orientation and
aria-valuenow/aria-valuemin/aria-valuemax. It is keyboard-operable: focus the handle and use
the arrow keys to resize (hold Shift for a coarser step), following the WAI-ARIA window
splitter pattern. When snaps is set, the arrow keys move between the snap points instead
(Shift / Home / End jump to the ends).
PlumaSplitView extends BoxInitial percentages for the flexible panes, in DOM order, for the uncontrolled case. When omitted, flexible panes split the available space equally.
Default:true
Disables resizing for the entire split. Panes still reflow when hidden.
Fires continuously while a resizer is being dragged, with the live pane percentages.
Fires once a resize gesture is committed (pointer up / keyboard change). Use this to persist a user's layout.
Fires when the layout changes in the controlled case. Mirror of sizes.
Default:'horizontal'
The axis panes are laid out and resized along. horizontal splits into columns,
vertical splits into rows.
Controlled percentages for the flexible panes, in DOM order. When provided the
consumer owns the layout and must update it from onSizesChange.
Snap points, as percentages of the flexible space. When set, dragging a resizer moves the boundary discretely between these points (the nearest one to the pointer) rather than resizing smoothly.
PlumaSplitViewPane extends BoxInitial size for the uncontrolled case. See SplitViewPaneSize.
A stable identity for the pane. Used to remember a pane's size across renders and, with
useStoredSplitView, to key persisted layouts. Give conditionally-rendered panes an
explicit id so each configuration is tracked and restored independently; when omitted,
an automatic id is generated. In React it is also forwarded as the element's id.
Default:false
When true, the pane collapses to zero and the remaining panes take its space. The
pane stays mounted. Toggling this is the consumer's responsibility.
Default:true
When false, this pane keeps its size and its adjacent resizers are inert.
Maximum size this pane may be resized to. Pixels (number / '200px') or percentage
('20%').
Minimum size this pane may be resized to. Pixels (number / '200px') or percentage
('20%').
Controlled size. See SplitViewPaneSize for how units are interpreted. A fixed
(pixel) size makes this a non-flexing track.
PlumaSplitViewResizer extends BoxDefault:false
Disables this specific resizer.
Default:true
Renders a visible grip affordance in the center of the resizer.