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: MouseEventinfo: EventInfo

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

onHoverEnd(event, info): void

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

event: MouseEventinfo: 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 }} />

On this page

Copyright © 2022 Framer B.V.

Cookies

Security

Terms of Service

Privacy Statement

Copyright © 2022 Framer B.V.

Cookies

Security

Terms of Service

Privacy Statement

Copyright © 2022 Framer B.V.

Cookies

Security

Terms of Service

Privacy Statement