Skip to main content

Client Passive Event Listeners

Source: .agents/references/coding-standard/vercel-react-best-practices/rules/client-passive-event-listeners.md

Metadata

  • title: Use Passive Event Listeners for Scrolling Performance
  • impact: MEDIUM
  • impactDescription: eliminates scroll delay caused by event listeners
  • tags: client, event-listeners, scrolling, performance, touch, wheel

Content

Use Passive Event Listeners for Scrolling Performance

Add { passive: true } to touch and wheel event listeners to enable immediate scrolling. Browsers normally wait for listeners to finish to check if preventDefault() is called, causing scroll delay.

Incorrect:

useEffect(() => {
const handleTouch = (e: TouchEvent) => console.log(e.touches[0].clientX)
const handleWheel = (e: WheelEvent) => console.log(e.deltaY)

document.addEventListener('touchstart', handleTouch)
document.addEventListener('wheel', handleWheel)

return () => {
document.removeEventListener('touchstart', handleTouch)
document.removeEventListener('wheel', handleWheel)
}
}, [])

Correct:

useEffect(() => {
const handleTouch = (e: TouchEvent) => console.log(e.touches[0].clientX)
const handleWheel = (e: WheelEvent) => console.log(e.deltaY)

document.addEventListener('touchstart', handleTouch, { passive: true })
document.addEventListener('wheel', handleWheel, { passive: true })

return () => {
document.removeEventListener('touchstart', handleTouch)
document.removeEventListener('wheel', handleWheel)
}
}, [])

Use passive when: tracking/analytics, logging, any listener that doesn't call preventDefault().

Don't use passive when: implementing custom swipe gestures, custom zoom controls, or any listener that needs preventDefault().