How touch-action: pan-y Handles Scroll and Swipes

The CSS touch-action: pan-y property allows web applications to retain smooth native vertical page scrolling while simultaneously capturing horizontal swipe gestures with JavaScript. By explicitly declaring the allowed touch interactions directly in CSS, the browser can immediately separate vertical scrolling from horizontal movements without waiting for JavaScript execution, eliminating scroll lag and gesture conflicts.

The Problem with Default Touch Handling

By default, mobile browsers handle all touch gestures directly on the viewport. When a user places a finger on the screen and drags, the browser must decide whether the gesture is meant to scroll the page, zoom, or interact with an element on the screen.

Before the touch-action property, developers handled swipe gestures by listening to touchstart, touchmove, and touchend events in JavaScript. To prevent the page from moving horizontally or behaving unpredictably, developers often called event.preventDefault(). However, calling preventDefault() inside touch listeners forces the browser to wait for the JavaScript thread to finish before deciding whether to scroll, resulting in delayed, stuttering, or janky scrolling behavior.

How touch-action: pan-y Solves the Issue

The touch-action property informs the browser's compositor thread about which touch interactions are allowed on a specific element before any JavaScript touch event handlers are executed.

When you apply touch-action: pan-y to an element:

  1. Vertical Panning Remains Native: The browser retains full native control over vertical scrolling (pan-y). When a user swipes up or down, the browser immediately scrolls the viewport smoothly without consulting the main JavaScript thread.
  2. Horizontal Panning Is Relinquished: The browser disables its own default actions for horizontal movements (pan-x). The browser will not attempt to scroll horizontally or trigger native navigation gestures like swiping back or forward through browser history.
  3. Gestures Pass Directly to JavaScript: Because the browser knows it will not handle horizontal panning natively, it immediately sends all horizontal pointer and touch events directly to your application logic.

Implementing Horizontal Swipes with pan-y

This property is ideal for UI components like carousels, image sliders, tab switchers, and swipe-to-dismiss items.

.carousel-container {
  touch-action: pan-y;
  overflow: hidden;
}

With this CSS rule applied, you can attach pointer event listeners in JavaScript to track horizontal movement:

const carousel = document.querySelector('.carousel-container');
let startX = 0;

carousel.addEventListener('pointerdown', (e) => {
  startX = e.clientX;
});

carousel.addEventListener('pointerup', (e) => {
  const diffX = e.clientX - startX;
  if (diffX > 50) {
    // Swipe right action
  } else if (diffX < -50) {
    // Swipe left action
  }
});

Performance and Usability Advantages

  • Jank-Free Scrolling: The browser does not need to wait for event listeners to resolve before executing vertical scrolls, ensuring the user experiences standard 60fps or 120fps scrolling.
  • Passive Event Listeners: Because you do not need to call event.preventDefault() to stop horizontal viewport shifting, you can safely use passive event listeners ({ passive: true }), which further improves rendering performance.
  • Predictable User Experience: Users can naturally scroll past interactive horizontal components while reading a page, but the moment their gesture aligns horizontally, the component responds instantly without accidental page shifting.