motion-solid

Drag

The drag prop makes a motion element follow the pointer. When it's released, it keeps its momentum and slows down, and it can be kept inside an area.

Making an element draggable

<motion.div drag />

drag moves the element in both directions. drag="x" and drag="y" limit it to one axis.

The element moves with the x and y transforms, so its layout doesn't change. Pass motion values as style={{ x, y }} to read or set its position (see Motion values).

Motion also sets a few styles on a draggable element: user-select: none, so dragging doesn't select text, and touch-action, so touch screens don't scroll the page while dragging (none for drag, pan-y for drag="x", pan-x for drag="y").

A drag doesn't start from an input, select or textarea inside the element, so those stay usable.

Constraints

dragConstraints limits where the element can go. It accepts two kinds of values.

An element. The draggable element stays inside it. Pass the element, an accessor of it (like a signal set by ref), or a { current } object:

The constraints are measured again when either element changes size, or when the window is resized.

Pixel bounds. An object with top, left, right and bottom, each optional, measured from the element's starting position:

<motion.div drag="x" dragConstraints={{ left: -100, right: 100 }} />

Elasticity

dragElastic sets how far the element can be pulled past its constraints, as a fraction of the pointer's movement. 0 stops it at the edge, 1 lets it follow the pointer. When released, it springs back inside. It's 0.35 by default. An object with top, left, right and bottom sets it per edge.

Momentum

When released, the element continues with the pointer's velocity and slows down with an inertia animation. dragMomentum={false} stops it where it's released.

dragTransition configures the inertia. For example, modifyTarget changes where the element comes to rest, here to snap to steps of 60 pixels:

x: 0px

bounceStiffness and bounceDamping set the spring at the constraints, power and timeConstant how far and how long it glides.

dragSnapToOrigin animates the element back to where it started when it's released. Set it to "x" or "y" to snap back on one axis only.

Direction lock

dragDirectionLock locks the drag to the axis the pointer first moves along. onDirectionLock is called with that axis ("x" or "y") once it's known:

Locked to: none

Nested draggable elements

By default, a pointer drags only one element: the innermost draggable element it presses. With dragPropagation, pressing the element also drags its draggable parents.

Props

PropTypeDefaultDescription
dragboolean | "x" | "y"falseEnables dragging, on both axes or one.
whileDragtarget or variant namesAnimates while dragging.
dragConstraintselement, accessor, { current }, or bounds objectfalseThe area the element stays in.
dragElasticboolean | number | { top, left, right, bottom }0.35How far it can be pulled past the constraints. false is 0.
dragMomentumbooleantrueKeeps gliding after release.
dragTransitioninertia optionsConfigures the glide after release.
dragSnapToOriginboolean | "x" | "y"falseAnimates back to the start on release.
dragDirectionLockbooleanfalseLocks the drag to the first axis moved along.
dragPropagationbooleanfalseAlso drags draggable parents.
dragListenerbooleantruefalse stops pressing the element from starting a drag. See useDragControls.
dragControlsDragControlsStarts drags from elsewhere. See useDragControls.

Events

PropSignatureCalled when
onDragStart(event, info: PanInfo) => voidThe drag starts.
onDrag(event, info: PanInfo) => voidThe pointer moves during the drag.
onDragEnd(event, info: PanInfo) => voidThe pointer is released.
onDirectionLock(axis: "x" | "y") => voidWith dragDirectionLock, the axis is known.
onDragTransitionEnd() => voidThe glide after release has finished.
onMeasureDragConstraints(constraints: BoundingBox) => BoundingBox | voidConstraints from an element have been measured. Return new bounds to change them.

info has the pointer's point, delta, offset and velocity, like the pan gesture. For example, info.velocity.x in onDragEnd tells how fast the element was thrown.