Splitter

Two or more panes divided by draggable, adjustable handles, sized in percent.

Open Source

Installation

Splitter ships with the library — install it once, then import:

import { Splitter } from "@delacour/react-native-ui/splitter";

Or copy the source into your project, to own and edit it:

bunx delacour@latest add splitter

Usage

app/index.tsx
import { Splitter } from "@/components/ui/splitter";
import { Text } from "@/components/ui/text";
import { View } from "react-native";

export default function Example() {
  return (
    <View className="flex-1 p-4">
      <Splitter className="h-96" defaultLayout={[35, 65]}>
        <Splitter.Pane minSize={20} maxSize={50}>
          <Text.Label>Sidebar</Text.Label>
        </Splitter.Pane>
        <Splitter.Handle accessibilityLabel="Resize sidebar" />
        <Splitter.Pane minSize={40}>
          <Text.Label>Detail</Text.Label>
        </Splitter.Pane>
      </Splitter>
    </View>
  );
}

The root needs an extent

Sizes are percentages of the box, so give the root flex-1 or a fixed height. A splitter with no size divides nothing.

Drag a seam

A drag moves only the two panes beside the handle and settles on the nearest step; a double tap resets.

Anatomy

Panes

variant="panes" gives each pane its own card surface, with a gap in place of the seam's rule.

Panes
<Splitter className="h-64" variant="panes">
  <Splitter.Pane />
  <Splitter.Handle />
  <Splitter.Pane />
</Splitter>

Three columns

Any number of panes, one handle between each pair; a handle moves only the two panes beside it.

Three columns
<Splitter className="h-64" defaultLayout={[25, 50, 25]}>
  <Splitter.Pane minSize={15} />
  <Splitter.Handle accessibilityLabel="Resize files" />
  <Splitter.Pane minSize={30} />
  <Splitter.Handle accessibilityLabel="Resize inspector" />
  <Splitter.Pane minSize={15} />
</Splitter>

Vertical

orientation="vertical" stacks the panes and drags along y.

Vertical
<Splitter className="h-80" orientation="vertical" defaultLayout={[60, 40]}>
  <Splitter.Pane minSize={25} />
  <Splitter.Handle accessibilityLabel="Resize editor" />
  <Splitter.Pane minSize={20} />
</Splitter>

Collapsible

A collapsible pane folds away once dragged past half its minSize, and useSplitter() can toggle it.

Collapsible
function ToggleSidebar() {
  const { togglePane } = useSplitter();
  return (
    <Button onPress={() => togglePane(0)}>
      <Button.Label>Toggle sidebar</Button.Label>
    </Button>
  );
}

<Splitter className="h-64">
  <Splitter.Pane isCollapsible minSize={25} maxSize={50} />
  <Splitter.Handle accessibilityLabel="Resize sidebar" />
  <Splitter.Pane minSize={40}>
    <ToggleSidebar />
  </Splitter.Pane>
</Splitter>

Controlled layout

onLayoutChange fires once per release, never per frame — the place to persist a layout.

const [layout, setLayout] = useState([30, 70]);

<Splitter layout={layout} onLayoutChange={setLayout}>
  <Splitter.Pane />
  <Splitter.Handle />
  <Splitter.Pane />
</Splitter>

Accessibility

Each handle is adjustable: it reads its label and the size of the pane before it, and offers increment, decrement, reset and — beside a collapsible pane — collapse or expand.

<Splitter step={10}>
  <Splitter.Pane />
  <Splitter.Handle accessibilityLabel="Resize navigation" />
  <Splitter.Pane />
</Splitter>

A double tap on a handle resets the layout.

Splitter or SplitView

Splitter is the general engine: two or more panes, either axis, stopping where the finger lets go. SplitView is two stacked panes that settle on named snap points.

API Reference

Anatomy

PartWhat it is
SplitterOwns the layout, the measurement and the settle
Splitter.PaneOne region, sized in percent, with an optional floor, ceiling and collapse
Splitter.HandleThe draggable, adjustable seam between the pane before it and the pane after it

Splitter

Prop

Type

Splitter.Pane

Prop

Type

Splitter.Handle

Prop

Type

useSplitter

Prop

Type

On this page