simoong·blog

Debugging pointermove on iOS Safari — Understanding the Cause and How to Fix It

image

Why pointermove isn't detected on mobile and a definitive solution (Issue discovered during RealGrid Calendar development)

Recently, while improving the Calendar component of RealGrid,

I discovered an unexpected phenomenon.

I was developing a feature that changes the month or year by swiping left or right with a finger.

The code, which worked fine on desktop, **did not respond at all in Safari mobile.

I had clearly implemented the pointermove event detection,

but no event was detected on iPhone.
After much debugging, we discovered that the cause was the default gesture handling of touch events.

--

💡 Why isn't pointermove detected on mobile?

When you move your finger on a mobile device, the browser first considers:

  1. Is this a scroll gesture?

  2. Is it pinch-zoom?

  3. Or did you simply touch the screen?

During this decision-making process, the browser prioritizes the default gesture.

This means that any action recognized as scrolling isn't received as a pointermove event to developers.

iOS Safari, in particular, is very conservative in this policy.
If it determines a touch gesture as "scrolling or navigation,"
pointermove isn't called at all.

Ultimately, we must disable the default touch gesture

to fully receive pointermove.


🧭 There are only two definitive solutions.

1️⃣ Controlling gestures with CSS — touch-action: none;

.calendar-body {
touch-action: none;
-ms-touch-action: none; /* IE/Edge legacy support */
}

This property means, "In this area, the browser should not scroll or zoom, but rather pass pointer input as is."

In fact, when I set
touch-action: none; to the RealGrid calendar body (.calendar-body),
pointermove events began to be detected properly when swiping. 🎉

This method resolves gesture conflicts with just one line,
is the most standard approach, and doesn't impact performance.

2️⃣ Directly Controlling in JS — preventDefault() + { passive:false }

const calendar = document.querySelector('.calendar-body');
 
calendar.addEventListener('touchmove', (e) => {
e.preventDefault(); // Prevent default scroll gesture
}, { passive: false });

This method declares "I'll handle this touch" at the JavaScript level.
However, you must specify { passive:false }.
Otherwise, preventDefault() will be ignored in iOS Safari, making it ineffective.

⚙️ Which method should I use?
If possible, I recommend using CSS touch-action.
This is declarative and easy to maintain.

However, if you need to detect swipe gestures, like in a calendar, and precisely calculate touch coordinates,
it's better to use preventDefault() in conjunction with this method.

In the RealGrid calendar, I opened the pointer with
touch-action: none;
and then used JavaScript to detect the pointermove coordinates and change the month and year based on the distance moved.

🧩 RealGrid Case Study
Here's a simple example I used during development:

calendar.addEventListener('pointerdown', (e) => {
startX = e.clientX;
});
 
calendar.addEventListener('pointermove', (e) => {
if (!startX) return;
const delta = e.clientX - startX;
if (delta > 80) changeMonth(-1); // Left swipe → Previous month
if (delta < -80) changeMonth(1); // Right swipe → Next month
}); ```
 
It worked perfectly on the desktop, but on iPhone Safari, no matter how I moved my finger, pointermove wasn't called even once.
 
However, adding the following line solved everything:
 
```css
.calendar-body { touch-action: none; }

After that, swiping became perfectly synchronized on both iOS and Android.

Thanks to this experience, I was able to apply the same principle to RealGrid's other draggable UIs (e.g., charts, cell resizing) to improve stability.

🧠 Summary: Things to Remember

Category Content
Cause of the Problem The browser prioritizes touch gestures (scroll/zoom)
Representative Symptom pointermove does not occur in iOS Safari
1st Solution touch-action: none;
2nd Solution preventDefault() + { passive:false } in touchmove
Application Examples RealGrid calendar swipe, chart drag, slider, etc.

💬 In conclusion
This issue isn't a simple browser bug,
but rather a browser policy designed to protect the user experience (scrolling, navigation).
However, once you understand how it works,
you can fully control pointermove on mobile devices.

It's a small difference, but I've personally experienced how a single line,
touch-action: none;
can change the entire swipe UX.

I hope this article provides a small hint to developers struggling with the same issue. 😊

#pointermove #touchmove #touchAction #preventDefault #mobileweb #iOSSafari #AndroidChrome #RealGrid #calendardevelopment #frontend #webevent