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

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:
-
Is this a scroll gesture?
-
Is it pinch-zoom?
-
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,"
pointermoveisn'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