Motion
Back to framer.com
DocumentationAnimation
Gestures
Motion
Back to framer.com
Design and publish your first free site today.
Getting started
  • Introduction
  • Examples
Animation
  • Overview
  • Layout
  • Gestures
  • Scroll
  • Transition
Components
  • motion
  • AnimatePresence
  • LayoutGroup
  • LazyMotion
  • MotionConfig
  • Reorder
Motion values
  • Overview
  • useMotionValueEvent
  • useMotionTemplate
  • useScroll
  • useSpring
  • useTime
  • useTransform
  • useVelocity
  • useWillChange
Hooks
  • useAnimate
  • useAnimationFrame
  • useDragControls
  • useInView
  • useReducedMotion
Universal
  • animate
  • transform
  • stagger
  • Easing functions
3D
  • Introduction
  • LayoutCamera
  • LayoutOrthographicCamera
  • MotionCanvas
Guides
  • Accessibility
  • Reduce bundle size
  • Upgrade guides
Community
  • GitHub
  • Discord

Gestures

A powerful gesture recognition system for the browser.

Motion extends the basic set of event listeners provided by React with a simple yet powerful set of UI gesture recognisers.

It currently has support for hover, tap, pan and drag gesture detection. Each gesture has a series of event listeners that you can attach to your motion component.

#Animation helpers

motion components provide multiple gesture animation props: whileHover, whileTap, whileFocus, whileDrag and whileInView. These can define animation targets to temporarily animate to while a gesture is active.

<motion.button
whileHover={{
scale: 1.2,
transition: { duration: 1 },
}}
whileTap={{ scale: 0.9 }}
/>

All props can be set either as a target of values to animate to, or the name of any variants defined via the variants prop. Variants will flow down through children as normal.

<motion.button
whileTap="tap"
whileHover="hover"
variants={buttonVariants}
>
<svg>
<motion.path variants={iconVariants} />
</svg>
</motion.button>

motion components automatically manage the interplay between these while props. So for instance, if hovering starts and stops while the tap gesture is active, the tap gesture receives priority and any properties defined on both will remain in their tapped state.

Likewise, if both gestures are defined and tapping ends, the component will know to animate either to the state defined in whileHover, or the component's original state, depending on whether tapping ends inside or outside of the component.

#Propagation

Children can stop pointer events propagating to parent motion components using the Capture React props.

For instance, a child can stop drag and tap gestures and their related while animations from firing on parents by passing e.stopPropagation() to onPointerDownCapture.

<motion.div whileTap={{ scale: 2 }}>
<button onPointerDownCapture={e => e.stopPropagation()} />
</motion.div>

#A note on SVG filters

The while helper properties won't work on SVG filter components, as these elements don't have a physical presence and therefore don't receive events. To respond to gestures, you need to introduce React state to the component and attach listeners to the physical element.

const MyComponent = () => {
const [isHovered, setHovered] = useState(false)
// Simplified example
return (
<svg>
<image
filter="url(#blur)"
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
/>
<filter id="blur">
<motion.div
initial={false}
animate={{ stdDeviation: isHovered ? 0 : 2 }}
/>
</filter>
</svg>
)
}

#Hover

The hover gesture detects when a pointer hovers over or leaves a component.

It differs from onMouseEnter and onMouseLeave in that hover is guaranteed to only fire as a result of actual mouse events (as opposed to browser-generated mice events emulated from touch input).

<motion.a
whileHover={{ scale: 1.2 }}
onHoverStart={e => {}}
onHoverEnd={e => {}}
/>

#whileHover: VariantLabels | TargetAndTransition

Properties or variant label to animate to while the hover gesture is recognised.

<motion.div whileHover={{ scale: 1.2 }} />

#onHoverStart(event, info): void

Callback function that fires when pointer starts hovering over the component.

event: MouseEvent

info: EventInfo

<motion.div onHoverStart={() => console.log('Hover starts')} />

#onHoverEnd(event, info): void

Callback function that fires when pointer stops hovering over the component.

event: MouseEvent

info: EventInfo

<motion.div onHoverEnd={() => console.log("Hover ends")} />

#Focus

The focus gesture detects when a component gains or loses focus by the same rules as the CSS :focus-visible selector.

Typically, this is when an input receives focus by any means, and when other elements receive focus by accessible means (like via keyboard navigation).

<motion.a
whileFocus={{ scale: 1.2 }}
href="#"
/>

#whileFocus: VariantLabels | TargetAndTransition

Properties or variant label to animate to while the focus gesture is recognised.

<motion.input whileFocus={{ scale: 1.2 }} />

#Tap

The tap gesture detects when the primary pointer (like a left click or first touch point) presses down and releases on the same component.

It fires a tap event when tapping successfully completes on a component, and a tapCancel event when tapping ends outside the component.

If the tappable component is a child of a draggable component, it'll automatically cancel the tap gesture if the pointer moves further than 3 pixels during the gesture.

#Accessibility

Elements with tap events are keyboard-accessible.

Any element with a tap prop will be able to receive focus and Enter can be used to trigger tap events on focused elements.

  • Pressing Enter down will trigger onTapStart and whileTap
  • Releasing Enter will trigger onTap
  • If the element loses focus before Enter is released, onTapCancel will fire.

#whileTap: VariantLabels | TargetAndTransition

Properties or variant label to animate to while the component is pressed.

<motion.div whileTap={{ scale: 0.8 }} />

#onTap(event, info): void

Callback when the tap gesture successfully ends on this element.

event: MouseEvent | TouchEvent | PointerEvent

The originating pointer event

info: TapInfo

A TapInfo object containing x and y values for the point relative to the device or page

function onTap(event, info) {
console.log(info.point.x, info.point.y)
}
<motion.div onTap={onTap} />

#onTapStart(event, info): void

Callback when the tap gesture starts on this element.

event: MouseEvent | TouchEvent | PointerEvent

The originating pointer event

info: TapInfo

A TapInfo object containing x and y values for the point relative to the device or page

function onTapStart(event, info) {
console.log(info.point.x, info.point.y)
}
<motion.div onTapStart={onTapStart} />

#onTapCancel(event, info): void

Callback when the tap gesture ends outside this element.

event: MouseEvent | TouchEvent | PointerEvent

The originating pointer event

info: TapInfo

A TapInfo object containing x and y values for the point relative to the device or page

function onTapCancel(event, info) {
console.log(info.point.x, info.point.y)
}
<motion.div onTapCancel={onTapCancel} />

#Pan

The pan gesture recognises when a pointer presses down on a component and moves further than 3 pixels. The pan gesture is ended when the pointer is released.

<motion.div onPan={(e, pointInfo) => {}} />

#onPan(event, info): void

Callback function that fires when the pan gesture is recognised on this element.

Note: For pan gestures to work correctly with touch input, the element needs touch scrolling to be disabled on either x/y or both axis with the touch-action CSS rule.

event: MouseEvent | TouchEvent | PointerEvent

The originating pointer event

info: PanInfo

A PanInfo object containing x and y values for:

  • point: Relative to the device or page.
  • delta: Distance moved since the last event.
  • offset: Offset from the original pan event.
  • velocity: Current velocity of the pointer.
function onPan(event, info) {
console.log(info.point.x, info.point.y)
}
<motion.div onPan={onPan} />

#onPanStart(event, info): void

Callback function that fires when the pan gesture begins on this element.

event: MouseEvent | TouchEvent | PointerEvent

The originating pointer event

info: PanInfo

A PanInfo object containing x and y values for:

  • point: Relative to the device or page.
  • delta: Distance moved since the last event.
  • offset: Offset from the original pan event.
  • velocity: Current velocity of the pointer.
function onPanStart(event, info) {
console.log(info.point.x, info.point.y)
}
<motion.div onPanStart={onPanStart} />

#onPanEnd(event, info): void

Callback function that fires when the pan gesture ends on this element.

event: MouseEvent | TouchEvent | PointerEvent

The originating pointer event

info: PanInfo

A PanInfo object containing x and y values for:

  • point: Relative to the device or page.
  • delta: Distance moved since the last event.
  • offset: Offset from the original pan event.
  • velocity: Current velocity of the pointer.
function onPanEnd(event, info) {
console.log(info.point.x, info.point.y)
}
<motion.div onPanEnd={onPanEnd} />

#Drag

The drag gesture follows the rules of the pan gesture but applies pointer movement to the x and/or y axis of the component.

<motion.div drag />

#whileDrag: VariantLabels | TargetAndTransition

Properties or variant label to animate to while the drag gesture is recognised.

<motion.div whileDrag={{ scale: 1.2 }} />

#drag: boolean | "x" | "y"

Enable dragging for this element. Set to false by default. Set true to drag in both directions. Set "x" or "y" to only drag in a specific direction.

<motion.div drag="x" />

#dragConstraints: false | Partial<BoundingBox2D> | RefObject<Element>

Applies constraints on the permitted draggable area.

It can accept an object of optional top, left, right, and bottom values, measured in pixels. This will define a distance the named edge of the draggable component.

Alternatively, it can accept a ref to another component created with React's useRef hook. This ref should be passed both to the draggable component's dragConstraints prop, and the ref of the component you want to use as constraints.

// In pixels
<motion.div
drag="x"
dragConstraints={{ left: 0, right: 300 }}
/>
// As a ref to another component
const MyComponent = () => {
const constraintsRef = useRef(null)
return (
<motion.div ref={constraintsRef}>
<motion.div drag dragConstraints={constraintsRef} />
</motion.div>
)
}

#dragSnapToOrigin: boolean

If true, the draggable element will animate back to its center/origin when released.

#dragElastic: DragElastic

The degree of movement allowed outside constraints. 0 = no movement, 1 = full movement.

Set to 0.5 by default. Can also be set as false to disable movement.

By passing an object of top/right/bottom/left, individual values can be set per constraint. Any missing values will be set to 0.

<motion.div
drag
dragConstraints={{ left: 0, right: 300 }}
dragElastic={0.2}
/>

#dragMomentum: boolean

Apply momentum from the pan gesture to the component when dragging finishes. Set to true by default.

<motion.div
drag
dragConstraints={{ left: 0, right: 300 }}
dragMomentum={false}
/>

#dragTransition: InertiaOptions

Allows you to change dragging inertia parameters. When releasing a draggable Frame, an animation with type inertia starts. The animation is based on your dragging velocity. This property allows you to customize it.

<motion.div
drag
dragTransition={{ bounceStiffness: 600, bounceDamping: 10 }}
/>

#dragPropagation: boolean

Allows drag gesture propagation to child components. Set to false by default.

<motion.div drag="x" dragPropagation />

#dragControls: DragControls

Usually, dragging is initiated by pressing down on a component and moving it. For some use-cases, for instance clicking at an arbitrary point on a video scrubber, we might want to initiate dragging from a different component than the draggable one.

By creating a dragControls using the useDragControls hook, we can pass this into the draggable component's dragControls prop. It exposes a start method that can start dragging from pointer events on other components.

const dragControls = useDragControls()
function startDrag(event) {
dragControls.start(event, { snapToCursor: true })
}
return (
<>
<div onPointerDown={startDrag} />
<motion.div drag="x" dragControls={dragControls} />
</>
)

Note: Given that by setting dragControls you are taking control of initiating the drag gesture, it is possible to disable the draggable element as the initiator by setting dragListener={false}.

#dragListener: boolean

Determines whether to trigger the drag gesture from event listeners. If passing dragControls, setting this to false will ensure dragging can only be initiated by the controls, rather than a pointerdown event on the draggable element.

#onDrag(event, info): void

Callback function that fires when the component is dragged.

event: MouseEvent | TouchEvent | PointerEvent

info: PanInfo

<motion.div
drag
onDrag={
(event, info) => console.log(info.point.x, info.point.y)
}
/>

#onDragStart(event, info): void

Callback function that fires when dragging starts.

event: MouseEvent | TouchEvent | PointerEvent

info: PanInfo

<motion.div
drag
onDragStart={
(event, info) => console.log(info.point.x, info.point.y)
}
/>

#onDragEnd(event, info): void

Callback function that fires when dragging ends.

event: MouseEvent | TouchEvent | PointerEvent

info: PanInfo

<motion.div
drag
onDragEnd={
(event, info) => console.log(info.point.x, info.point.y)
}
/>

#onDirectionLock(axis): void

Callback function that fires a drag direction is determined.

axis: "x" | "y"

<motion.div
drag
dragDirectionLock
onDirectionLock={axis => console.log(axis)}
/>
PreviousLayout animationsNextScroll animations
On this page
  • Animation helpers
  • Propagation
  • A note on SVG filters
  • Hover
  • Focus
  • Tap
  • Accessibility
  • Pan
  • Drag

Copyright © 2022 Framer B.V.

  • Security
  • Terms of Service
  • Privacy Statement