Documentation

Drag Interactions

Make elements draggable with motionwind utility classes -- axis locking, elasticity, visual feedback, and advanced drag patterns.

Drag Interactions

motionwind provides built-in classes for Motion's drag system. The Babel plugin translates drag classes into the drag, dragElastic, and whileDrag props on motion.* components.


Drag Axes

Horizontal Only

Lock dragging to the X axis with animate-drag-x. The element can only be moved left and right:

<div className="animate-drag-x w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  Drag me
</div>

Build output:

<motion.div drag="x" className="w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  Drag me
</motion.div>
Drag X Only

Vertical Only

Lock dragging to the Y axis with animate-drag-y. The element can only be moved up and down:

<div className="animate-drag-y w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  Drag me
</div>

Build output:

<motion.div drag="y" className="w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  Drag me
</motion.div>
Drag Y Only

Both Axes

Allow dragging in any direction with animate-drag-both:

<div className="animate-drag-both w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  Drag me
</div>

Build output:

<motion.div drag className="w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  Drag me
</motion.div>
Drag Both Axes

Drag Elasticity

The animate-drag-elastic-{n} class controls how much the element stretches past its constraints (or how snappily it returns to its origin). The value is a number from 0 to 100, mapped to a 0-1 range:

  • animate-drag-elastic-0 -- no elasticity, hard stop at boundaries
  • animate-drag-elastic-50 -- medium elasticity (default-like feel)
  • animate-drag-elastic-100 -- maximum elasticity, very stretchy
<div className="animate-drag-both animate-drag-elastic-20 w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  Low elastic
</div>

Build output:

<motion.div drag dragElastic={0.2} className="w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  Low elastic
</motion.div>
Drag Elasticity Comparison

Visual Feedback While Dragging

The animate-drag: gesture prefix lets you apply visual changes while the element is being actively dragged. This maps to Motion's whileDrag prop:

<div className="animate-drag-both animate-drag:scale-110 animate-drag:rotate-5 animate-spring w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  Drag me
</div>

Build output:

<motion.div
  drag
  whileDrag={{ scale: 1.1, rotate: 5 }}
  transition={{ type: "spring" }}
  className="w-16 h-16 rounded-xl bg-green-400 cursor-grab"
>
  Drag me
</motion.div>
Drag with Visual Feedback

You can combine whileDrag with other gestures. For example, a draggable element that also responds to hover:

<div className="animate-drag-both animate-drag:scale-110 animate-hover:scale-105 animate-hover:opacity-80 animate-spring w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  Multi-gesture
</div>
Drag + Hover Gestures Combined

Drag Constraints

The animate-drag-constraint-{side}-{n} classes define pixel boundaries that restrict how far an element can be dragged. Each side is set independently:

  • animate-drag-constraint-t-{n} -- top boundary
  • animate-drag-constraint-b-{n} -- bottom boundary
  • animate-drag-constraint-l-{n} -- left boundary
  • animate-drag-constraint-r-{n} -- right boundary
<div className="animate-drag-both animate-drag-constraint-t-100 animate-drag-constraint-b-100 animate-drag-constraint-l-100 animate-drag-constraint-r-100 w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  Constrained
</div>

Build output:

<motion.div
  drag
  dragConstraints={{ top: 100, left: 100, right: 100, bottom: 100 }}
  className="w-16 h-16 rounded-xl bg-green-400 cursor-grab"
>
  Constrained
</motion.div>

For ref-based constraints (constraining drag to a parent element), use the Motion API directly with a useRef and the dragConstraints prop.


Drag Snap to Origin

The animate-drag-snap class makes the element animate back to its original position when released. This maps to Motion's dragSnapToOrigin prop:

<div className="animate-drag-both animate-drag-snap w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  I snap back
</div>

Build output:

<motion.div
  drag
  dragSnapToOrigin
  className="w-16 h-16 rounded-xl bg-green-400 cursor-grab"
>
  I snap back
</motion.div>

Drag Momentum

By default, Motion applies momentum to dragged elements -- when you release, the element continues in the direction of the drag gesture. The animate-drag-no-momentum class disables this behavior so the element stops immediately on release:

<div className="animate-drag-both animate-drag-no-momentum w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  No momentum
</div>

Build output:

<motion.div
  drag
  dragMomentum={false}
  className="w-16 h-16 rounded-xl bg-green-400 cursor-grab"
>
  No momentum
</motion.div>

Drag Direction Lock

The animate-drag-lock class locks the drag to whichever axis the user starts dragging in. If the user begins dragging horizontally, the element will only move on the X axis for that gesture (and vice versa). This maps to Motion's dragDirectionLock prop:

<div className="animate-drag-both animate-drag-lock w-16 h-16 rounded-xl bg-green-400 cursor-grab">
  Locked
</div>

Build output:

<motion.div
  drag
  dragDirectionLock
  className="w-16 h-16 rounded-xl bg-green-400 cursor-grab"
>
  Locked
</motion.div>

Drag Reorder

Motion provides a dedicated Reorder component for creating drag-to-reorder lists. This is a higher-level abstraction built on top of the drag system and requires the Reorder.Group and Reorder.Item components:

import { Reorder } from "motion/react";
import { useState } from "react";

function ReorderList() {
  const [items, setItems] = useState(["Item 1", "Item 2", "Item 3", "Item 4"]);

  return (
    <Reorder.Group axis="y" values={items} onReorder={setItems}>
      {items.map((item) => (
        <Reorder.Item
          key={item}
          value={item}
          className="p-4 mb-2 bg-gray-800 rounded-lg cursor-grab"
          whileDrag={{ scale: 1.05, boxShadow: "0 8px 30px rgba(0,0,0,0.3)" }}
        >
          {item}
        </Reorder.Item>
      ))}
    </Reorder.Group>
  );
}

Since Reorder.Group and Reorder.Item are React components (uppercase), the motionwind Babel plugin skips them. Use the Motion API directly for reorderable lists.


Class Reference

ClassMotion outputDescription
animate-drag-xdrag="x"Horizontal dragging only
animate-drag-ydrag="y"Vertical dragging only
animate-drag-bothdragFree dragging on both axes
animate-drag-elastic-{n}dragElastic={n/100}Snap-back elasticity (0-100)
animate-drag-snapdragSnapToOriginSnap back to origin on release
animate-drag-no-momentumdragMomentum={false}Disable post-release momentum
animate-drag-lockdragDirectionLockLock to initial drag direction
animate-drag-constraint-t-{n}dragConstraints={{ top: n }}Top boundary
animate-drag-constraint-l-{n}dragConstraints={{ left: n }}Left boundary
animate-drag-constraint-r-{n}dragConstraints={{ right: n }}Right boundary
animate-drag-constraint-b-{n}dragConstraints={{ bottom: n }}Bottom boundary
animate-drag:scale-{n}whileDrag={{ scale: n/100 }}Scale while dragging
animate-drag:rotate-{n}whileDrag={{ rotate: n }}Rotate while dragging
animate-drag:opacity-{n}whileDrag={{ opacity: n/100 }}Opacity while dragging