Rohan Shewale's Blog

Swipping scroll lock hook

March 10, 2025 | 2 Minute Read

A useful hook to lock/unlock scrolling when swiping horizontally in mobile devices.

The hook returns touch event handlers - touchStartHandler, touchMoveHandler, touchEndHandler, which needs to be wired up with the element targeted to have isolated swiping action.

import { useCallback, useEffect, useState } from 'react';

/** A threshold value for y-swipe  */
const Y_SWIPING_THRESHOLD = 3;

/**
 * A hook to lock vertical scrolling of document body when swiping horizontally.
 */
export const useSwipingScrollLock = () => {
  const [touchStartX, setTouchStartX] = useState(0);
  const [preventingVerticalScroll, setPreventingVerticalScroll] = useState(false);

  useEffect(() => {
    document.body.style.overflow = preventingVerticalScroll ? 'hidden' : 'auto';
  }, [preventingVerticalScroll]);

  // cleanup & reset
  useEffect(() => {
    return () => {
      document.body.style.overflow = 'auto';
    };
  }, []);

  const touchStartHandler = () => (ev: TouchEvent) => {
    const touch = ev.changedTouches[0];
    setTouchStartX(touch.screenX);
  };

  const touchMoveHandler: any = useCallback(
    (ev: TouchEvent) => {
      const touch = ev.changedTouches[0];
      const touchEndX = touch.screenX;

      const swipeDistanceHorizontal = touchEndX - touchStartX;

      if (Math.abs(swipeDistanceHorizontal) > Y_SWIPING_THRESHOLD) {
        setPreventingVerticalScroll(true);
      } else {
        setPreventingVerticalScroll(false);
      }
    },
    [touchStartX]
  );

  const touchEndHandler = () => setPreventingVerticalScroll(false);

  return {
    touchStartHandler,
    touchMoveHandler,
    touchEndHandler,
  };
};