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>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>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 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 boundariesanimate-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>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>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 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 boundaryanimate-drag-constraint-b-{n}-- bottom boundaryanimate-drag-constraint-l-{n}-- left boundaryanimate-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
| Class | Motion output | Description |
|---|---|---|
animate-drag-x | drag="x" | Horizontal dragging only |
animate-drag-y | drag="y" | Vertical dragging only |
animate-drag-both | drag | Free dragging on both axes |
animate-drag-elastic-{n} | dragElastic={n/100} | Snap-back elasticity (0-100) |
animate-drag-snap | dragSnapToOrigin | Snap back to origin on release |
animate-drag-no-momentum | dragMomentum={false} | Disable post-release momentum |
animate-drag-lock | dragDirectionLock | Lock 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 |