Prevent Double Tap Zoom in React for Rapidly Tapped Buttons
Touch delay is a thing of the past, but accidental zooming is here to ruin your day. Ever tapped a button quickly on iOS and experienced a zoom instead of two taps? You're in the right place.
Before
After
Code
Just use this helper function to preventDefault
on double taps, while still
allowing for pinch to zoom and rapid scrolling.
// Ensure touches occur rapidly
const delay = 500
// Sequential touches must be in close vicinity
const minZoomTouchDelta = 10
// Track state of the last touch
let lastTapAt = 0
let lastClientX = 0
let lastClientY = 0
export default function preventDoubleTapZoom(event) {
// Exit early if this involves more than one finger (e.g. pinch to zoom)
if (event.touches.length > 1) {
return
}
const tapAt = new Date().getTime()
const timeDiff = tapAt - lastTapAt
const { clientX, clientY } = event.touches[0]
const xDiff = Math.abs(lastClientX - clientX)
const yDiff = Math.abs(lastClientY - clientY)
if (
xDiff < minZoomTouchDelta &&
yDiff < minZoomTouchDelta &&
event.touches.length === 1 &&
timeDiff < delay
) {
event.preventDefault()
// Trigger a fake click for the tap we just prevented
event.target.click()
}
lastClientX = clientX
lastClientY = clientY
lastTapAt = tapAt
}
Example Use
const TapAsFastAsYouWantButton = (children, ...rest) =>
<button {...props} onTouchStart={preventDoubleTapZoom}>
{children}
</button>
const Game = () =>
<TapAsFastAsYouWantButton onClick={fireLasers}>
Fire Lasers
</TapAsFastAsYouWantButton>
This comment has been minimized.
Hi @mutewinter! Great to see a potential fix to a problem that bothers me too! Do you think your solution can be used as a global preventor of all double clicks for all components? Similar to how
react-fastclick
works.UPD: Own solution: https://stackoverflow.com/a/46624015/1818285