All questions

Drag & Drop Sortable

Premium

Drag & Drop Sortable

Drag a row in a to-do list and the others slide to make room, landing it in a new slot. The visible part is animation; the brain is a tiny bit of geometry: as you drag, figure out which index the item should occupy right now. The trick that makes it feel right — no flicker, no jitter at boundaries — is using each item's midpoint: a neighbor only gets displaced once your cursor crosses the middle of it, not the moment you touch its edge. This is the core of SortableJS, dnd-kit, and every reorderable list.

Implement dragAndDropSortable(rects, fromIndex, pointerY) — pure math, no DOM.

Signature

function dragAndDropSortable(rects, fromIndex, pointerY) {
  return { toIndex, order }; // where it lands + the resulting index order
}

Examples

// 4 rows, 50px tall: midpoints 25, 75, 125, 175
dragAndDropSortable(rows, 0, 80);  // dragging row 0, cursor at y=80 (past midpoint 75)
// { toIndex: 1, order: [1, 0, 2, 3] }
dragAndDropSortable(rows, 0, 999); // dragged far below everything
// { toIndex: 3, order: [1, 2, 3, 0] }

Notes

  • Midpoint rule — an item is displaced only when pointerY crosses its midpoint (top + height/2), so hovering its top half doesn't swap yet. That hysteresis is what stops the flicker.
  • Target index = a counttoIndex is the number of other items (exclude the dragged one) whose midpoint sits above pointerY.
  • Index spacetoIndex is expressed in the list with the dragged item removed, i.e. the second argument to a move(from, to) splice; order is the reordered array of original indices.
  • Variable heights — compute each midpoint from its own rect; don't assume a uniform row height.

Unlock the solution & editor

  • Runnable editor + tests

    Solve in the browser with instant Jest feedback.

  • Detailed solutions

    Walkthroughs, edge cases, and complexity notes.

  • Multi-framework variants

    React, Vue, Vanilla, Angular — same question, different stacks.

Upgrade to Premium