Long Press in JavaScript?
Solution 1
There is no 'jQuery' magic, just JavaScript timers.
var pressTimer;
$("a").mouseup(function(){
clearTimeout(pressTimer);
// Clear timeout
return false;
}).mousedown(function(){
// Set timeout
pressTimer = window.setTimeout(function() { ... Your Code ...},1000);
return false;
});
Solution 2
Based on Maycow Moura's answer, I wrote this. It also ensures that the user didn't do a right click, which would trigger a long press and works on mobile devices. DEMO
var node = document.getElementsByTagName("p")[0];
var longpress = false;
var presstimer = null;
var longtarget = null;
var cancel = function(e) {
if (presstimer !== null) {
clearTimeout(presstimer);
presstimer = null;
}
this.classList.remove("longpress");
};
var click = function(e) {
if (presstimer !== null) {
clearTimeout(presstimer);
presstimer = null;
}
this.classList.remove("longpress");
if (longpress) {
return false;
}
alert("press");
};
var start = function(e) {
console.log(e);
if (e.type === "click" && e.button !== 0) {
return;
}
longpress = false;
this.classList.add("longpress");
if (presstimer === null) {
presstimer = setTimeout(function() {
alert("long click");
longpress = true;
}, 1000);
}
return false;
};
node.addEventListener("mousedown", start);
node.addEventListener("touchstart", start);
node.addEventListener("click", click);
node.addEventListener("mouseout", cancel);
node.addEventListener("touchend", cancel);
node.addEventListener("touchleave", cancel);
node.addEventListener("touchcancel", cancel);
You should also include some indicator using CSS animations:
p {
background: red;
padding: 100px;
}
.longpress {
-webkit-animation: 1s longpress;
animation: 1s longpress;
}
@-webkit-keyframes longpress {
0%, 20% { background: red; }
100% { background: yellow; }
}
@keyframes longpress {
0%, 20% { background: red; }
100% { background: yellow; }
}
Solution 3
You can use taphold event of jQuery mobile API.
jQuery("a").on("taphold", function( event ) { ... } )
Solution 4
I created long-press-event (0.5k pure JS) to solve this, it adds a long-press
event to the DOM.
Listen for a long-press
on any element:
// the event bubbles, so you can listen at the root level
document.addEventListener('long-press', function(e) {
console.log(e.target);
});
Listen for a long-press
on a specific element:
// get the element
var el = document.getElementById('idOfElement');
// add a long-press event listener
el.addEventListener('long-press', function(e) {
// stop the event from bubbling up
e.preventDefault()
console.log(e.target);
});
Works in IE9+, Chrome, Firefox, Safari & hybrid mobile apps (Cordova & Ionic on iOS/Android)
Solution 5
While it does look simple enough to implement on your own with a timeout and a couple of mouse event handlers, it gets a bit more complicated when you consider cases like click-drag-release, supporting both press and long-press on the same element, and working with touch devices like the iPad. I ended up using the longclick jQuery plugin (Github), which takes care of that stuff for me. If you only need to support touchscreen devices like mobile phones, you might also try the jQuery Mobile taphold event.
Randy Mayer
Updated on August 22, 2021Comments
-
Randy Mayer over 2 years
Is it possible to implement "long press" in JavaScript (or jQuery)? How?
(source: androinica.com)HTML
<a href="" title="">Long press</a>
JavaScript
$("a").mouseup(function(){ // Clear timeout return false; }).mousedown(function(){ // Set timeout return false; });
-
mattbasta about 14 yearsCouldn't have said it better myself.
-
Randy Mayer about 14 yearsAlso... You need to specify $("a").click(function(){ return false; });
-
Matti Virkkunen about 14 years
$(this).mouseup(function(){});
does not remove the event handler, it adds another one. Use.unbind
instead. -
Gallal over 11 yearsWouldn't this fire on a drag as well?
-
Angelo.Hannes over 11 yearsI tried to add this code to a the rendering div of a jQuery Mobile Flip Switch, which broke that switch.
-
David John Welsh over 10 years@Gallal Presumably it would be fairly simple to see to that by calling
clearTimeout(pressTimer)
onmousemove
, unless I'm missing something. Which admittedly would hardly be unprecendented. -
Ian about 9 years@DavidJohnWelsh Just what I've been looking at, you don't just want mouse move though - holding you finger dead steady and not moving 1px is quite hard! You need to apply a threshold (if mouse hasn't moved 10px) etc. Gets complicated quite quickly!
-
GajendraSinghParihar about 9 yearsthis is not retained in call.
-
user2075328 almost 9 yearshi Bro can we use it as a backbone event
-
pasx almost 9 yearsThis should be the accepted answer since jquery-mobile provides a good stable framework
-
Xander over 8 yearsI made this modified version, to do something constantly while the button is held down jsfiddle but for some reason on Android it runs even after you stop touching the + button...
-
kelunik over 8 years@Xander: Maybe because the
:hover
state is sticky on touch devices, maybe that also applies here. -
Xander over 8 yearsDang, I wonder if there's any way to get -/+ number increment buttons working on a mobile site that support long presses. Every method I find only supports having to click repeatedly which is a pain for huge numbers. Thanks though!
-
kelunik over 8 years@Xander: Actually,
touchend
should fire IMO, there's no reason to have it sticky when it's special code for touch devices, maybe I'll try something tomorrow. -
Xander over 8 yearsFigured out the issue on Android. Pressing fires both mousedown and touchstart so it had 2 timers running but only 1 being cancelled by lifting your finger. Wrapped presstimer with if (presstimer === null) to make sure timer wasn't already active.
-
kelunik over 8 years@Xander: Makes sense, could you edit the answer and add a note?
-
SuperNova over 8 years@Xander: presstimer should be set to null, after clearTimeout
-
Marcel Verwey about 8 yearsPlease note: jquery mobile conflicts with jquery ui. See also stackoverflow.com/questions/24379514/…
-
dfmiller about 8 yearsOr for JQuery use $(selector).bind('contextmenu', function() {})
-
jedi almost 8 yearsWhit this code the longclick is not fired at the end of 500ms. The user can die clicking on the mouse :). The long click is fired only if the user stop to click on the button.
-
dbinott almost 8 yearsshould use
off()
now instead of unbind. -
dbinott almost 8 yearsstop using
bind()
jquery 1.7+ =on()
andunbind()
=off()
-
dartacus over 7 yearsBear in mind that if you're expecting this to work on phones, they often have their own default longpress behaviour (chrome on android, for example, shows a modal menu with various options when you long press a link). I didn't have a lot of luck preventing this, and to be honest interfering with browser default behaviour is a hiding to nothing anyway.
-
arlomedia over 7 yearsThe Github link works, but the project hasn't been updated since 2010 and doesn't work with current jquery versions. However, replacing handle.apply with dispatch.apply in the source code fixes it.
-
eric xu almost 7 yearsnice solution for iOS
-
Smig almost 7 yearsI had to add a mouseout as well to clear the timeout, so that this only triggers if the press remains within the component's boundaries.
-
Jonathan Applebaum over 5 yearsthis is the best solution I have found so far. because it does not relay on any plugin or external library. It is just missing
node.addEventListener("mouseup", cancel);
when you need to increase some variable \ DOM element until the user leaves the mouse button. -
chen.w over 5 yearsMay a ask what is the purpose of 'return false' statement here for each function?
-
Jeff T. over 5 yearsOwesome, mate !!
-
Admin about 5 yearsThere are two problems with this technique: The timers are not cancelled if this is accompanied by a move event (drag element, or mobile gesture or moving out of element or off page to user interface or screen area in case of a windowed app mobile configuration), or if there are multiple touch points (combined with press and drag, i.e. pinch-zoom in or out). Also this doesn't seem to help Android/Chrome's (maybe others' too) penchant for going into text select mode on long press. Until or unless long-press is formally added to DOM Events spec, expect horrible bugs.
-
Admin about 5 yearsAlthough this is the selected answer, it is not really answering the question. It is overly simplistic and naive. Any long press event must address multiple issues which this answer ignores. 1) Distinguish long press from drag from gesture from multi touch (i.e. pinch zoom in or out) 2) Cancel if movement outside of element or browser area 3) Address default behavior of text selection on a significant number of platforms and devices 4) Allow a configurable threshhold for sensitivity and not rely upon magic numbers. Particularly helpful for - but not exclusive to - accessibility concerns.
-
Admin about 5 yearsThis solution monkey patches the window.CustomEvent object in a somewhat haphazard, incomplete and non-standard way. It does not properly create read-only properties as read-only but rather read-write. It is specifically missing returnValue, type, timeStamp and isTrusted. It does not address drag, gesture, pinch zoom in or out, or multi-touch misfires of long press, nor does it address the issue of a large number of devices and/or platforms which default long press to text selection even at 500ms. The library is missing any and all test cases for these conditions.
-
John Doherty about 5 yearsIt’s Open Source, feel free to contribute to the project :)
-
Akin Hwan almost 5 yearshow would I prevent touches that start on the thumbnail, but say end up being a scroll. in other words, not a touchstart/end in place, but a touch that started on the element with handler, but ends up being a scroll
-
Akin Hwan almost 5 yearswhat if user starting scrolling after mousedown, and wasn't intending to do a longpress
-
Akin Hwan almost 5 yearswould this cover the case when a user started scrolling instead of finishing their longpress in the same spot?
-
razz almost 5 years@AkinHwan No it would only get triggered if the mouse click was released over the same element.
-
Devashish almost 5 years@JohnDoherty great! but can we still use "onClick" with the same element?
-
John Doherty almost 5 yearsYou should still get the 'onclick' event so long as the long press is released before 'long-press-delay' timer kicks in
-
fred727 almost 4 yearsIf you want to disable click during long press, read this : stackoverflow.com/questions/56802461/…
-
Nazar Vynnytskyi over 3 yearsPlease check how it is implemented with handling edge cases in prod - docs.sencha.com/touch/2.1.1/source/…
-
Alex Hajnal over 2 yearsOr inline the HTML element:
oncontextmenu="callback();"
It's probably desirable to add e.g.event.preventDefault();
somewhere near the top of the callback function.