Skip to main content

Overview

The pan gesture recognizes pointer movement across the screen. Unlike drag, pan doesn’t move the element but provides detailed information about the pointer movement for custom implementations. Note: For pan gestures to work correctly with touch input, the element needs touch scrolling to be disabled on either x/y or both axes with the touch-action CSS rule.
.pan-element {
  touch-action: none; /* Disable touch scrolling */
}

Event Handlers

onPan

Callback function that fires when the pan gesture is recognized on this element.
type onPan = (event: PointerEvent, info: PanInfo) => void

interface PanInfo {
  point: { x: number; y: number }
  delta: { x: number; y: number }
  offset: { x: number; y: number }
  velocity: { x: number; y: number }
}
  • 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 (in px/ms)
function onPan(event, info) {
  console.log(info.point.x, info.point.y)
  console.log(info.delta.x, info.delta.y)
  console.log(info.offset.x, info.offset.y)
  console.log(info.velocity.x, info.velocity.y)
}

<motion.div onPan={onPan} />

onPanStart

Callback function that fires when the pan gesture begins on this element.
type onPanStart = (event: PointerEvent, info: PanInfo) => void
function onPanStart(event, info) {
  console.log('Pan started at', info.point.x, info.point.y)
}

<motion.div onPanStart={onPanStart} />

onPanEnd

Callback function that fires when the pan gesture ends on this element.
type onPanEnd = (event: PointerEvent, info: PanInfo) => void
function onPanEnd(event, info) {
  console.log('Final velocity:', info.velocity.x, info.velocity.y)
}

<motion.div onPanEnd={onPanEnd} />

onPanSessionStart

Callback function that fires when we begin detecting a pan gesture. This is analogous to onMouseStart or onTouchStart.
type onPanSessionStart = (event: PointerEvent, info: EventInfo) => void

interface EventInfo {
  point: { x: number; y: number }
}
function onPanSessionStart(event, info) {
  console.log('Session started at', info.point)
}

<motion.div onPanSessionStart={onPanSessionStart} />

Examples

Custom slider

function Slider() {
  const [value, setValue] = useState(0)
  const constraintsRef = useRef(null)

  return (
    <div
      ref={constraintsRef}
      style={{
        width: '300px',
        height: '4px',
        backgroundColor: '#e0e0e0',
        position: 'relative'
      }}
    >
      <motion.div
        onPan={(event, info) => {
          const percentage = (info.point.x / 300) * 100
          setValue(Math.max(0, Math.min(100, percentage)))
        }}
        style={{
          width: '20px',
          height: '20px',
          borderRadius: '50%',
          backgroundColor: '#007bff',
          position: 'absolute',
          top: '-8px',
          left: `${value}%`,
          touchAction: 'none'
        }}
      />
    </div>
  )
}

Track swipe velocity

function SwipeDetector() {
  const handlePanEnd = (event, info) => {
    const swipeThreshold = 0.5 // px/ms
    
    if (Math.abs(info.velocity.x) > swipeThreshold) {
      if (info.velocity.x > 0) {
        console.log('Swiped right')
      } else {
        console.log('Swiped left')
      }
    }
  }

  return (
    <motion.div
      onPanEnd={handlePanEnd}
      style={{ touchAction: 'pan-y' }} // Allow vertical scroll
    >
      Swipe left or right
    </motion.div>
  )
}

Pan-based drawing

function DrawingCanvas() {
  const [path, setPath] = useState([])

  return (
    <svg width="400" height="400">
      <motion.path
        d={path.join(' ')}
        stroke="black"
        fill="none"
        strokeWidth="2"
      />
      <motion.rect
        width="400"
        height="400"
        fill="transparent"
        onPanSessionStart={(event, info) => {
          setPath([`M ${info.point.x} ${info.point.y}`])
        }}
        onPan={(event, info) => {
          setPath(prev => [...prev, `L ${info.point.x} ${info.point.y}`])
        }}
        style={{ touchAction: 'none' }}
      />
    </svg>
  )
}

PanInfo Properties

point

Contains x and y values for the current pan position relative to the device or page.
point: { x: number; y: number }

delta

Contains x and y values for the distance moved since the last event.
delta: { x: number; y: number }

offset

Contains x and y values for the distance moved from the first pan event.
offset: { x: number; y: number }

velocity

Contains x and y values for the current velocity of the pointer, in px/ms.
velocity: { x: number; y: number }

Build docs developers (and LLMs) love