Terracotta
GitHub
import {
  Splitter,
  SplitterPane,
  SplitterSeparator,
  SplitterStateChild,
  useSplitterState,
} from 'terracotta/splitter';

Anatomy

<Splitter>             {/* owns the size of the primary pane */}
  <SplitterPane/>      {/* the primary pane */}
  <SplitterSeparator/> {/* role="separator", focusable, draggable */}
  <div/>               {/* the other pane; no component needed */}
</Splitter>

Examples

Basic

Sizing the panes

The value runs from min to max, 0 to 100 by default, so it reads as a percentage. Size the primary pane from it:

<Splitter class="splitter" defaultValue={30}>
  {state => (
    <>
      <SplitterPane style={{ 'flex-basis': `${state.value()}%` }}>…</SplitterPane>
      <SplitterSeparator aria-label="Contents" />
      <div style={{ flex: 1 }}>…</div>
    </>
  )}
</Splitter>

A drag sets the value from the pointer's place across the whole splitter, so the panes should fill it.

Naming the separator

The pattern names the separator after the primary pane. Point aria-labelledby at the pane's heading, or give it an aria-label:

<SplitterSeparator aria-labelledby="contents-heading" />

Stacked panes

horizontal stacks the panes, so the separator is a horizontal line that ↑ and ↓ move. The primary pane is the top one.

Limits and collapsing

min and max limit the primary pane. Enter moves the separator to min, and moves it back to where it was on the next Enter. With the default min of 0, that collapses the pane completely. While the pane is at min, it and the separator carry tc-collapsed.

Controlled

const [size, setSize] = createSignal(30);

<Splitter value={size()} onChange={setSize}>…</Splitter>

State attributes

Element Attribute Present when
Splitter tc-splitter Always
SplitterPane tc-splitter-pane Always
SplitterSeparator tc-splitter-separator Always
Splitter tc-horizontal The panes are stacked
SplitterPane, SplitterSeparator tc-collapsed The primary pane is at min
Splitter, SplitterSeparator tc-disabled The splitter is disabled

Reading the state in code

Member Type Description
value() number The size of the primary pane.
min() / max() / step() number The range, and how far an arrow key moves.
collapsed() boolean Whether the primary pane is at min.
disabled() boolean Whether the splitter is disabled.
setValue(value) (number) => void Sets the size, kept in range.
grow(steps?) / shrink(steps?) (number?) => void Moves by a number of steps, 1 by default.
toggle() () => void Collapses the primary pane, or restores it.

You can reach this state as the render-prop argument on any part, through <SplitterStateChild>, or with useSplitterState() inside any descendant component.

Keyboard

Handled on the separator:

Key Action
← / → Moves the separator left / right, when the panes are side by side
↑ / ↓ Moves the separator up / down, when the panes are stacked
Enter Collapses the primary pane, or restores it
Home / End Gives the primary pane its smallest / largest size

In right-to-left text the primary pane is on the right, and the arrow keys still move the separator the way they point.

API

<Splitter>

Renders a <div> by default. Pass exactly one of defaultValue or value.

Prop Type Default Description
as ValidConstructor 'div' Element or component to render as.
defaultValue number none Initial size of the primary pane, uncontrolled.
value number none Current size, controlled.
min number 0 The smallest size.
max number 100 The largest size.
step number 5 How far an arrow key moves the separator.
horizontal boolean false Stacks the panes.
disabled boolean false Blocks changes.
onChange (value: number) => void none Called with the new size.
ref DynamicNode<T> | (el) => void none Handle to the rendered element.
children JSX.Element | (state: SplitterStateProperties) => JSX.Element none Contents, or a render prop.
…rest props of as none Forwarded to the rendered element.

<SplitterPane>

Renders a <div> by default, with a generated id that the separator points aria-controls at.

<SplitterSeparator>

Renders a <div> by default.

Rendered attributes: role="separator", tabindex="0" (-1 while disabled), aria-orientation, aria-valuenow, aria-valuemin, aria-valuemax, aria-controls, aria-disabled, tc-splitter-separator.

Every part takes as, ref and children, and forwards the rest of its props.