usePinchZoom

A hook to handle pinch-to-zoom gestures on touch devices.

Made by raouf.codes
Edit on GitHub

Overview

The usePinchZoom hook provides pinch-to-zoom gesture handling for touch devices. It tracks two-finger touch gestures and calculates zoom levels with configurable min/max bounds.

Installation

Usage

Basic

import { useRef, useState } from 'react';
import { usePinchZoom } from '@/hooks/use-pinch-zoom';

function ZoomableImage() {
  const containerRef = useRef<HTMLDivElement>(null);
  const [zoom, setZoom] = useState(1);

  usePinchZoom({
    elementRef: containerRef,
    onZoom: setZoom,
  });

  return (
    <div ref={containerRef} style={{ touchAction: 'none' }}>
      <img
        src="/image.jpg"
        alt="Zoomable"
        style={{ transform: `scale(${zoom})` }}
      />
    </div>
  );
}

With Custom Bounds

function ImageViewer() {
  const containerRef = useRef<HTMLDivElement>(null);
  const [zoom, setZoom] = useState(1);

  usePinchZoom({
    elementRef: containerRef,
    onZoom: setZoom,
    minZoom: 0.25,
    maxZoom: 5,
    initialZoom: 1,
  });

  return (
    <div
      ref={containerRef}
      className="overflow-hidden"
      style={{ touchAction: 'none' }}
    >
      <div style={{ transform: `scale(${zoom})`, transformOrigin: 'center' }}>
        <img src="/photo.jpg" alt="Photo" />
      </div>
    </div>
  );
}

With Reset Button

function ZoomableContent() {
  const containerRef = useRef<HTMLDivElement>(null);
  const [zoom, setZoom] = useState(1);

  usePinchZoom({
    elementRef: containerRef,
    onZoom: setZoom,
    initialZoom: zoom,
  });

  return (
    <div>
      <button onClick={() => setZoom(1)}>Reset Zoom</button>
      <div ref={containerRef} style={{ touchAction: 'none' }}>
        <div style={{ transform: `scale(${zoom})` }}>{/* Content */}</div>
      </div>
    </div>
  );
}

API Reference

usePinchZoom

function usePinchZoom(options: UsePinchZoomOptions): void;

UsePinchZoomOptions

PropTypeDefault
elementRef
React.RefObject<HTMLElement | null>
-
onZoom
function
-
minZoom?
number
0.5
maxZoom?
number
3
initialZoom?
number
1

Touch Events

The hook handles the following touch events:

  • touchstart — Records initial pinch distance when two fingers touch
  • touchmove — Calculates new zoom based on finger distance change
  • touchend/touchcancel — Resets pinch tracking when gesture ends

Styling Tips

For smooth zooming, consider these CSS properties:

.zoomable-container {
  touch-action: none; /* Prevent browser gestures */
  overflow: hidden;
}

.zoomable-content {
  transform-origin: center;
  transition: transform 0.1s ease-out; /* Optional smoothing */
}

Features

  • Bounded zoom — Configurable min and max zoom levels
  • Smooth gestures — Calculates zoom based on pinch distance ratio
  • Prevents conflicts — Calls preventDefault() to stop page zooming
  • Clean cleanup — Removes all touch listeners on unmount

Browser Support

Pinch zoom works on all modern touch-enabled browsers:

  • iOS Safari
  • Android Chrome
  • Touch-enabled laptops

Credits

  • Based on standard touch gesture handling patterns

Built by raouf.codes. The source code is available on GitHub.

Last updated: 2/27/2026

On this page