Skip to the solution
MediumMachine Coding11 min read

Build Resizable Panels with useResizable Hook

415 views

The problem

Question presented to candidate: "Our editor has a file sidebar next to the main area. Build a draggable divider so users can resize the sidebar, and package the logic as a reusable hook, something like const { size, handleProps } = useResizable({ initial: 280, min: 180, max: 480 }). It should work with a mouse, touch and the keyboard, and remember the width."

Requirements:

  • A sidebar and a main area with an 8 px divider between them; dragging the divider changes the sidebar width.
  • Width clamped between min and max no matter where the pointer goes, including far outside the window.
  • Pointer events (mouse, touch, pen), only for the primary button, with no text selection while dragging.
  • Keyboard: the divider is focusable; Left and Right change the width by a step, Shift for a bigger step, Home and End jump to min and max; double-click resets.
  • Proper separator semantics: role="separator", aria-valuenow, aria-valuemin, aria-valuemax, aria-controls.
  • The width persists in localStorage, written when a drag ends rather than on every move, and storage failures do not break the widget.
  • The logic lives in a reusable hook (or composable or directive) with a small API.

What a strong answer should cover:

  • Computing the size from the drag's start position (startSize + clientX - startX) rather than accumulating deltas, so it cannot drift.
  • Listening for pointermove and pointerup on window (or using setPointerCapture) so a fast drag that leaves the handle keeps working, and removing those listeners on pointerup, pointercancel and unmount.
  • touch-action: none on the handle so touch drags do not scroll the page.
  • Clamping, and what to do when max is larger than the space available.
  • Hook API design: returning prop getters versus spreading an object, and keeping persistence optional.
  • Accessibility of the window splitter pattern.

Clarifying questions expected:

  • "Horizontal only, or should the hook support vertical resizing too?"
  • "Should the width persist per user, per page or not at all?"
  • "Are there several panels, or exactly one handle?"

Code / implementation expected: Yes. The hook and a two-panel layout using it.

  • React
  • Resizable
  • useResizable
  • Layout

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

11 min read ยท 9 sections

React solution

Every file of the working solution. Open it in the playground to run and change it.

ReactComplete solution
import { useResizable } from "./src/hooks/useResizable";

export default function App() {
  const { size, dragging, handleProps } = useResizable({
    initial: 280,
    min: 180,
    max: 480,
    step: 10,
    storageKey: "demo-sidebar-width",
  });

  return (
    <div className={"layout" + (dragging ? " is-dragging" : "")}>
      <aside
        id="sidebar"
        className="sidebar"
        style={{ width: size }}
        data-testid="sidebar"
      >
        <h2>Files</h2>
        <ul>
          <li>index.html</li>
          <li>styles.css</li>
          <li>a-very-long-file-name-that-wraps.js</li>
        </ul>
      </aside>
      <div
        {...handleProps}
        className="handle"
        aria-label="Resize sidebar"
        aria-controls="sidebar"
      />
      <main className="content">
        <h1>Editor</h1>
        <p data-testid="size">Sidebar width: {size}px</p>
        <p className="hint">
          Drag the bar, or focus it and use the arrow keys (Shift for bigger
          steps), Home and End. Double-click resets.
        </p>
      </main>
    </div>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 59 of 107 in Machine coding

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextMedium

Build a Toast Notification system

Continue