Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Prevent Double Tap Zoom in React for Rapidly Tapped Buttons

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

Before

After

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>
@kachkaev

This comment has been minimized.

Copy link

commented Oct 7, 2017

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

@jonathanmv

This comment has been minimized.

Copy link

commented Dec 19, 2017

My double tap to zoom was still happening after using this function and a warning was shown in the console

Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080

Based on this answer I set the touch-action: none; in the element's css and it worked for me. I haven't tested it thoroughly though.

@thaytharma

This comment has been minimized.

Copy link

commented Oct 2, 2018

Hey, do you have anything similar working for Vue.Js 2?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.