Detect a finger swipe through JavaScript on the iPhone and Android
Solution 1
Simple vanilla JS code sample:
document.addEventListener('touchstart', handleTouchStart, false);
document.addEventListener('touchmove', handleTouchMove, false);
var xDown = null;
var yDown = null;
function getTouches(evt) {
return evt.touches || // browser API
evt.originalEvent.touches; // jQuery
}
function handleTouchStart(evt) {
const firstTouch = getTouches(evt)[0];
xDown = firstTouch.clientX;
yDown = firstTouch.clientY;
};
function handleTouchMove(evt) {
if ( ! xDown || ! yDown ) {
return;
}
var xUp = evt.touches[0].clientX;
var yUp = evt.touches[0].clientY;
var xDiff = xDown - xUp;
var yDiff = yDown - yUp;
if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
if ( xDiff > 0 ) {
/* right swipe */
} else {
/* left swipe */
}
} else {
if ( yDiff > 0 ) {
/* down swipe */
} else {
/* up swipe */
}
}
/* reset values */
xDown = null;
yDown = null;
};
Tested in Android.
Solution 2
Simple vanilla JS example for horizontal swipe:
let touchstartX = 0
let touchendX = 0
function checkDirection() {
if (touchendX < touchstartX) alert('swiped left!')
if (touchendX > touchstartX) alert('swiped right!')
}
document.addEventListener('touchstart', e => {
touchstartX = e.changedTouches[0].screenX
})
document.addEventListener('touchend', e => {
touchendX = e.changedTouches[0].screenX
checkDirection()
})
You can use pretty same logic for vertical swipe.
Solution 3
I merged a few of the answers here into a script that uses CustomEvent to fire swiped events in the DOM. Add the 0.7k swiped-events.min.js script to your page and listen for swiped events:
swiped
document.addEventListener('swiped', function(e) {
console.log(e.target); // the element that was swiped
console.log(e.detail.dir); // swiped direction
});
swiped-left
document.addEventListener('swiped-left', function(e) {
console.log(e.target); // the element that was swiped
});
swiped-right
document.addEventListener('swiped-right', function(e) {
console.log(e.target); // the element that was swiped
});
swiped-up
document.addEventListener('swiped-up', function(e) {
console.log(e.target); // the element that was swiped
});
swiped-down
document.addEventListener('swiped-down', function(e) {
console.log(e.target); // the element that was swiped
});
You can also attach directly to an element:
document.getElementById('myBox').addEventListener('swiped-down', function(e) {
console.log(e.target); // the element that was swiped
});
Optional config
You can specify the following attributes to tweak how swipe interaction functions in your page (these are optional).
<div data-swipe-threshold="10"
data-swipe-timeout="1000"
data-swipe-ignore="false">
Swiper, get swiping!
</div>
To set defaults application wide, set config attributes on topmost element:
<body data-swipe-threshold="100" data-swipe-timeout="250">
<div>Swipe me</div>
<div>or me</div>
</body>
Source code is available on Github
Solution 4
Based on @givanse's answer, this is how you could do it with classes
:
class Swipe {
constructor(element) {
this.xDown = null;
this.yDown = null;
this.element = typeof(element) === 'string' ? document.querySelector(element) : element;
this.element.addEventListener('touchstart', function(evt) {
this.xDown = evt.touches[0].clientX;
this.yDown = evt.touches[0].clientY;
}.bind(this), false);
}
onLeft(callback) {
this.onLeft = callback;
return this;
}
onRight(callback) {
this.onRight = callback;
return this;
}
onUp(callback) {
this.onUp = callback;
return this;
}
onDown(callback) {
this.onDown = callback;
return this;
}
handleTouchMove(evt) {
if ( ! this.xDown || ! this.yDown ) {
return;
}
var xUp = evt.touches[0].clientX;
var yUp = evt.touches[0].clientY;
this.xDiff = this.xDown - xUp;
this.yDiff = this.yDown - yUp;
if ( Math.abs( this.xDiff ) > Math.abs( this.yDiff ) ) { // Most significant.
if ( this.xDiff > 0 ) {
this.onLeft();
} else {
this.onRight();
}
} else {
if ( this.yDiff > 0 ) {
this.onUp();
} else {
this.onDown();
}
}
// Reset values.
this.xDown = null;
this.yDown = null;
}
run() {
this.element.addEventListener('touchmove', function(evt) {
this.handleTouchMove(evt).bind(this);
}.bind(this), false);
}
}
You can than use it like this:
// Use class to get element by string.
var swiper = new Swipe('#my-element');
swiper.onLeft(function() { alert('You swiped left.') });
swiper.run();
// Get the element yourself.
var swiper = new Swipe(document.getElementById('#my-element'));
swiper.onLeft(function() { alert('You swiped left.') });
swiper.run();
// One-liner.
(new Swipe('#my-element')).onLeft(function() { alert('You swiped left.') }).run();
Solution 5
I have found @givanse brilliant answer to be the most reliable and compatible across multiple mobile browsers for registering swipe actions.
However, there's a change in his code required to make it work in modern day mobile browsers that are using jQuery
.
event.touches
won't exist if jQuery
is used and results in undefined
and should be replaced by event.originalEvent.touches
. Without jQuery
, event.touches
should work fine.
So the solution becomes,
document.addEventListener('touchstart', handleTouchStart, false);
document.addEventListener('touchmove', handleTouchMove, false);
var xDown = null;
var yDown = null;
function handleTouchStart(evt) {
xDown = evt.originalEvent.touches[0].clientX;
yDown = evt.originalEvent.touches[0].clientY;
};
function handleTouchMove(evt) {
if ( ! xDown || ! yDown ) {
return;
}
var xUp = evt.originalEvent.touches[0].clientX;
var yUp = evt.originalEvent.touches[0].clientY;
var xDiff = xDown - xUp;
var yDiff = yDown - yUp;
if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
if ( xDiff > 0 ) {
/* left swipe */
} else {
/* right swipe */
}
} else {
if ( yDiff > 0 ) {
/* up swipe */
} else {
/* down swipe */
}
}
/* reset values */
xDown = null;
yDown = null;
};
Tested on:
- Android: Chrome, UC Browser
- iOS: Safari, Chrome, UC Browser
827
Updated on December 12, 2021Comments
-
827 over 2 years
How can you detect that a user swiped his finger in some direction over a web page with JavaScript?
I was wondering if there was one solution that would work for websites on both the iPhone and an Android phone.
-
Volomike over 13 yearsI believe it's touchstart, touchmove, touchcancel, and touchend that one would work with, not mousedown or mouseup.
-
Niklas Ekman over 10 yearsIf one does not want jQuery mobile to manipulate the UI, see: stackoverflow.com/questions/8648596/…
-
d.raev about 10 yearsLooks cool and simple, any idea what is the support for this events
touchstart
,touchmove
? -
Philip G over 9 yearsI also needed to add:
$.event.special.swipe.scrollSupressionThreshold = 8;
but you put me in the right direction! Thank you! -
Codebeat about 9 yearsIt works pretty well but has a problem detecting straight movements. I will post another answer at this topic that fixed this as JQuery (desktop) solution. It also adds the mouse version of these swipe events and add a sensitivity option.
-
Codebeat about 9 yearsDamn. Topic is closed so cannot add my answer!
-
Peter Eisentraut over 8 yearsThis works great, but left/right and up/down are backwards.
-
mrid over 7 yearsWorks great !! Any idea how to get the exact distance swiped ?? I tried using yDiff for swipe down, but it keeps giving me different values for almost equal swipes.
-
nick.skriabin over 7 yearsthis code probably wont work because you'll get an exception while trying to call
.bind
of undefined because yourhandleTouchMove
actually didn't return anything. also it's useless to call bind when calling function withthis.
because it's already bound to current context -
quantumpotato over 7 yearsI tried this - when I swipe the page scrolls instead of the event triggering
-
Jan Derk about 7 yearsoriginalEvent is a JQuery property. It should be left out if you run pure javascript without JQuery. The current code raises an exception if run without JQuery.
-
Jan Derk about 7 yearsoriginalEvent is a JQuery property. It does not even exist in pure Javascript.
-
nashcheez about 7 yearsAs per this SO answer, a touch event if supported by the browser will be exposed through
event.originalEvent
. The thing isevent.touches
has ceased to exist now and results inundefined
. -
Jan Derk about 7 yearsevent.touches only ceased to exist when using JQuery. Try your code without JQuery and you will get an error that evt.originalEvent is undefined. JQuery totally replaces event with its own and puts the native browser event in originalevent. Short version: Your code only works with JQuery. It works without JQuery if you remove originalevent.
-
nashcheez about 7 yearsYeah I researched a bit and realized you were right about the availability of jquery enabling
event.originalEvent
. I will update my answer. Thanks! :) -
Ali Ghanavatian almost 7 yearsI just removed
.bind(this);
and it worked gracefully. thank you @nicholas_r -
iiic over 6 yearsIt works good also on desktop Chrome with touchscreen (on Windows). But there's already build-in function makes history back and history forward on same gestures. It's possible to turn it off, but you'r mess with user which expecting different behaviour.
-
StefanBob about 6 yearsI came here because pure-swipe was not working for me on MOBILE
-
John Doherty over 5 years@StefanBob if you raise a tick on the github repo with enough information to allow me to reproduce the issue, I will look into it
-
Blue Tram over 5 yearsPart get the element yourself I just remove '#' in document.getElementById('my-element') and it worked good. Thank you @Marwelln :)
-
TetraDev about 5 yearsIf you want to wait until the swipe ENDS (meaning after they lift their finger or onmouseup), change
touches[0]
tochangedTouches[0]
and the event handler typehandleTouchMove
tohandleTouchEnd
-
Mat about 5 yearscall
run()
twice and you get a nasty memory leak -
kishore kingmaker over 4 years@Marwelln Hi Marwelln, can you say where you got this code from?
-
collimarco over 4 yearsThanks, it works perfectly! I replaced Hammer.js with your library, because the former doesn't work with browser zoom and that is a serious usability issue. With this library the zoom works properly (tested on Android)
-
collimarco over 4 yearsA problem with this is that it does not consider the size of the gesture: even a small gesture (of a few pixels) may cause an involuntary swipe...
-
1.21 gigawatts over 4 yearsIs this for ES5 or ES6?
-
Trendal Toews over 4 years@gigawatts I don't recall. The project that used that has reached EOL already and I haven't needed the code since. I suspect at the time I was writing for ES6 but that was over 2 years ago.
-
NMALM about 4 yearsCurrently using this version. How would I prevent this from firing multiple times if swiped in repetition? I utilize this with the animate feature for a sidescrolling form and when I swipe multiple times, things get a bit screwy and my divs start overlapping in the visible area.
-
Panagiss about 4 yearsif
preventDefault()
is added the touch controls sometimes get wrong coords!! -
Kviz Majster almost 4 yearsChanged xDown = evt.originalEvent.touches[0].clientX; yDown = evt.originalEvent.touches[0].clientY; to xDown = evt.offsetX; yDown = evt.offsetY; and now it works like charm on normal JS. I like this solution.
-
user1090751 over 3 yearshow do we know the div where swipe is started?
-
AlexandreS over 3 yearsHammer.js doesn't seem to be maintained anymore
-
Basj over 3 years@collimarco See my answer below, derived from this one; it solves this problem.
-
Basj over 3 yearsIf you do a touch "pinch zoom" with two fingers, one finger nearly fixed, and the other finger moving away, I think it is detected as a "swipe" by this code... Isn't it?
-
Vivi over 3 yearsAny chance you can add an example usage?
-
smlnl over 3 yearsHow can we make this work for every "class" ? // One-liner. (new Swipe('.everyElementHasThisClass')).onLeft(function() { alert('You swiped left.') }).run();
-
NiceToMytyuk over 3 yearshow could i add a range before the swipe event will be casted? like if it's just a small right or left movment i have to ignore it while when it's significant i have to cast it
-
givanse over 3 yearsxDiff and yDiff would be the numbers to gate under a treshold
-
codepleb about 3 yearsLol this is so simple and even allows to specify a "travel distance".
-
Mattia Rasulo about 3 yearsBest answer by far.. it's a shame it doesn't have more upvotes..
-
Dgloria almost 3 yearsThis is perfect.
-
Mystogan over 2 years@MattiaRasulo maybe need to add up and down swipe
-
Henry James over 2 yearsthis is some real nice code, if you want to do up and down all you need to do is change where it states X and replace with Y. Easyyyy
-
Philipp Moers over 2 yearsGreat answer because of its simplicity! It may be worth noting that also vertical swipes are detected as horizontal swipes with this code if touch points have a minimal x distance.
-
Zahidul Islam Ruhel about 2 years@JohnDoherty would you extend it so it also works on desktop(non-touch) devices.
-
grepgrok about 2 yearsIt should be noted that "right swipe" is referring to swiping right-to-left, the same goes for the rest of the swipes: [listed]-to-[opposite].