Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
Back to tool/Back to issues
#3823·motion

[BUG] Reorder.Item with dragConstraints gets a faulty drag offset on window resize

Author: nmck257Created Sep 14, 2026Updated Sep 14, 2026
Labelsbug

Describe the bug

A Reorder.Item that has never been dragged gets a non-zero x (and z-index: 1) applied whenever the window resizes, as long as dragConstraints is a ref object. The items visually shift out of their layout positions and begin to overlap, so pointer hit-testing no longer matches what the user sees — clicking one item selects another. The first pointerdown on each item snaps that item back to its origin, so the problem clears itself one item at a time, one bad click each.

IMPORTANT: Provide a CodeSandbox reproduction of the bug

Apologies, I'm in a corporate network and can't access CodeSandbox (https://codesandbox.io/). But I do have a code snippet that can be pasted in there:

javascript
import React, { useRef, useState } from 'react';
import { Reorder } from 'framer-motion';
export function App() {
  const containerRef = useRef(null);
  const [items, setItems] = useState(['one', 'two', 'three', 'four', 'five']);
  const [selected, setSelected] = useState('one');
  return (
    <Reorder.Group
      ref={containerRef}
      axis="x"
      values={items}
      onReorder={setItems}
      style={{ display: 'flex', gap: 8, listStyle: 'none', padding: 8, margin: 0 }}
    >
      {items.map((item) => (
        <Reorder.Item
          key={item}
          value={item}
          dragConstraints={containerRef}
          style={{ border: '1px solid #999', background: selected === item ? '#bcd' : '#eee' }}
        >
          <button type="button" style={{ padding: '10px 18px' }} onClick={() =>
            setSelected(item)}>
            {item}
          </button>
        </Reorder.Item>
      ))}
    </Reorder.Group>
  );
}

Steps to reproduce

  1. Load at a window width where the items fit comfortably (~1200px).
  2. Narrow the window until the row is tight (~500px). Don't drag anything.
  3. Every <li> now has an inline transform: translateX(px) and z-index: 1.
  4. Click an item — a different one gets selected. Click again — the right one is selected.

Expected behavior

An item that is not being dragged and is resting at its origin should keep x === 0 across a resize. z-index should stay unset.

Video or screenshots

N/A

Environment details

Windows, Chrome

Notes

Claude had a recommended root cause fix; here's its analysis:

VisualElementDragControls.scalePositionWithinConstraints() is wired to a window resize listener and to ResizeObservers on the element and the constraints element (addListeners()), and it never checks whether a drag is in progress:

typescript
eachAxis((axis) => {
    if (!shouldDrag(axis, drag, null)) return;
    const axisValue = this.getAxisMotionValue(axis);
    const { min, max } = this.constraints[axis];
    axisValue.set(mixNumber(min, max, boxProgress[axis]));
});

boxProgress is captured earlier as the element's position expressed as a fraction of the old constraints box. For an element resting at the origin, x === 0 is not a meaningful fraction of that box — so re-projecting it into the newly measured box yields a non-zero value. The function's stated purpose ("reposition the element within those new constraints relative to where it was before the resize") is correct for an element with a real offset, but for one at its origin there is no offset to preserve. Confirmed by wrapping the item's x MotionValue and capturing the write: value=480.998 at ReorderItemComponent.point.x.set at eachAxis at VisualElementDragControls.scalePositionWithinConstraints at <window "resize" listener>

Suggested fix: In VisualElementDragControls.scalePositionWithinConstraints():

typescript
...
const axisValue = this.getAxisMotionValue(axis);
if (!this.isDragging && axisValue?.get() === 0) return;
const { min, max } = (this.constraints as ResolvedConstraints)[
   axis
] as Axis
...

This is deliberately narrower than gating the whole function on isDragging, which would also stop a genuinely-offset draggable from being kept inside its constraints on resize. We've been running this as a build-time patch; it fixes the resize trigger, and drag-to-reorder is unaffected.

Impact: This affects any Reorder list with ref-based dragConstraints. One example in the wild: GraphiQL 5 renders each query tab as a Reorder.Item with dragConstraints={tabContainerRef}, so every GraphiQL user has to click each tab twice after any resize, zoom, or panel toggle.

Source: motiondivision/motion

View original on GitHubView discussion on GitHub