Skip to content

Instantly share code, notes, and snippets.

@mutewinter
Last active December 8, 2021 11:01
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mutewinter/b86fc06bae43fd3e13169bfb569b06b1 to your computer and use it in GitHub Desktop.
Save mutewinter/b86fc06bae43fd3e13169bfb569b06b1 to your computer and use it in GitHub Desktop.
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>
@Coridyn
Copy link

Coridyn commented Apr 24, 2020

There is a pure CSS fix that may work also: touch-action: manipulation;

The MDN page on touch-action describes it:

"[manipulation] disable[s] additional non-standard gestures such as double-tap to zoom. Disabling double-tap to zoom removes the need for browsers to delay the generation of click events when the user taps the screen."

It's also well supported; available since iOS 9.3 and Android Chrome 36.

@pspEgg
Copy link

pspEgg commented Jul 11, 2020

There is a pure CSS fix that may work also: touch-action: manipulation;

The MDN page on touch-action describes it:

"[manipulation] disable[s] additional non-standard gestures such as double-tap to zoom. Disabling double-tap to zoom removes the need for browsers to delay the generation of click events when the user taps the screen."

It's also well supported; available since iOS 9.3 and Android Chrome 36.

This answer worked for me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment