Next Chapter Begins 🚀Read the full story

useSplitter

Hook that manages resizable panel layout with keyboard navigation and pointer-based resizing.

Panel 1
Panel 2
basic-demo

Usage#

import { useSplitter } from '@primereact/headless/splitter';
const { rootProps, getPanelProps, getGutterProps, handleProps } = useSplitter({
    panels: [{ minSize: 10 }, { minSize: 10 }],
    defaultSizes: [30, 70]
});
 
<div {...rootProps} style={{ display: 'flex' }}>
    <div {...getPanelProps(0)} />
    <div {...getGutterProps(0)}>
        <div {...handleProps} />
    </div>
    <div {...getPanelProps(1)} />
</div>;

useSplitter manages panel sizing, drag-to-resize, keyboard resizing, and collapse behavior, see Primitive for a component-based API.

Features#

  • Declarative panel config, pass panels with minSize, maxSize, collapsible, and collapsedSize per pane instead of wiring constraints yourself
  • Pointer and keyboard resizing, getGutterProps(index) returns an ARIA separator with drag, arrow key, Home/End, and Enter handlers already attached
  • Horizontal or vertical orientation, one flag switches axis, key mappings, and the data attributes you style against
  • Controlled or uncontrolled sizes, feed sizes + onResize/onResizeEnd for external state or let the hook manage it from defaultSizes
  • Collapsible panes, panels snap to collapsedSize when dragged below their minimum, no extra logic required
  • Resize-in-progress signal, state.resizing plus data-resizing lets you switch cursors and disable selection during a drag

Working with callbacks#

Controlled sizes#

Feed sizes with onResizeEnd (fires after drag completes) or onResize (fires continuously) for external state.

const [sizes, setSizes] = React.useState([50, 50]);
 
const splitter = useSplitter({
    panels: [{ minSize: 10 }, { minSize: 10 }],
    sizes,
    onResizeEnd: (e) => setSizes(e.sizes)
});

Persisting layout across reloads#

Pair onResizeEnd with localStorage to restore the user's layout on next visit.

const [sizes, setSizes] = React.useState(() => JSON.parse(localStorage.getItem('layout') ?? '[30,70]'));
 
useSplitter({
    panels: [{ minSize: 10 }, { minSize: 10 }],
    sizes,
    onResizeEnd: (e) => {
        setSizes(e.sizes);
        localStorage.setItem('layout', JSON.stringify(e.sizes));
    }
});

Collapsible side panel#

Mark a panel collapsible and give it a collapsedSize so dragging below minSize snaps it closed instead of getting stuck.

const splitter = useSplitter({
    panels: [{ minSize: 15, collapsible: true, collapsedSize: 5 }, { minSize: 10 }],
    defaultSizes: [30, 70]
});

Fine-grained keyboard resizing#

Lower step when precise keyboard adjustments matter, the default of 5 moves the gutter 5% per arrow press.

const splitter = useSplitter({
    panels: [{ minSize: 10 }, { minSize: 10 }],
    step: 1
});

Vertical orientation#

orientation: 'vertical' swaps the axis and rebinds arrow keys automatically.

const splitter = useSplitter({
    panels: [{ minSize: 10 }, { minSize: 10 }],
    orientation: 'vertical'
});

Styling with data attributes#

The root exposes data-orientation, data-resizing, and data-disabled so cursor and selection rules can stay in CSS.

[data-orientation='horizontal'][data-resizing] {
    cursor: col-resize;
    user-select: none;
}
[data-orientation='vertical'][data-resizing] {
    cursor: row-resize;
    user-select: none;
}
[data-disabled] {
    pointer-events: none;
    opacity: 0.4;
}

API#

useSplitter#

NameTypeDefault

Accessibility#

Arrow keys resize the panes, Home/End collapse to min/max, and Enter toggles between preset sizes. See Primitive for full WAI-ARIA compliance details.