Resizable Split PaneLoading saved progress…

Resizable Split Pane

Build two panes side by side, separated by a draggable vertical divider, as a single React component. Dragging the divider left or right resizes the panes: the left pane's width follows the pointer, clamped to a sensible 20%–80% range, and the right pane fills whatever is left. A label under the split reads the current ratio, e.g. 50% / 50%.

Task

The starter App.tsx renders the split at a fixed 50 / 50 with no drag logic. Make the divider work:

  1. Hold the state. Track leftPct with useState(50) and a dragging boolean. Keep a ref to the .split container so you can read its size.
  2. Start the drag. On the divider's onPointerDown, set dragging and add pointermove + pointerup listeners on window — not on the divider — so the drag keeps tracking when the cursor leaves the thin handle.
  3. Follow the pointer. In the move handler, read the container's getBoundingClientRect() and set leftPct = clamp(round((clientX - left) / width * 100), 20, 80).
  4. End the drag. On pointerup, clear dragging and remove both window listeners.

Examples

  • Load: the divider sits in the middle, both panes equal, label 50% / 50%.
  • Drag the divider right: the left pane grows, the label counts up (64% / 36%), and it stops at 80% / 20% no matter how far you drag.
  • Drag left: the left pane shrinks and stops at 20% / 80%.

Notes

  • Listen on window, not the divider. The handle is only 8px wide; if the listeners lived on it, a fast drag would outrun the cursor and drop. window hears every move until pointerup.
  • The rect gives you the frame. getBoundingClientRect() returns the container's left and width in the same coordinate space as clientX, so the subtraction and division line up.
  • Clamp, then render. Clamping to 20–80 keeps either pane from collapsing; the right pane is pure flex: 1, so you only ever set the left width.
  • Styling (dark theme, panes, divider) is already in styles.css; focus on the state and the pointer math.
Loading editor…
Loading preview…