140

Is it possible to implement "long press" in JavaScript (or jQuery)? How?

alt text
(source: androinica.com)

HTML

<a href="" title="">Long press</a>

JavaScript

$("a").mouseup(function(){
  // Clear timeout
  return false;
}).mousedown(function(){
  // Set timeout
  return false; 
});
2
  • 7
    I'd probably create custom jQuery event using your code as a base, so you can just do jQuery(...).longclick(function() { ... }); Commented Apr 12, 2010 at 20:39
  • 3
    The question is not tagged with jQuery, although it should be. The question asks first for a pure Javascript solution, which I prefer, or optionally (in parenthesis), a jQuery solution. Most answers seem to default to jQuery as a standard assumption. I have always despised jQuery and never once used it nor felt any compelling need for it. Some enjoy using it, that is fine, to each their own. Answers using either technique hurt nothing. But since the question will accept jQuery solutions, a jQuery tag might get more eyeballs and hopefully better answers. The jQuery answers here seem lackluster.
    – user2895783
    Commented Mar 29, 2019 at 13:44

20 Answers 20

182

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; 
});
11
  • 50
    Wouldn't this fire on a drag as well?
    – Gallal
    Commented Aug 9, 2012 at 17:18
  • 17
    @Gallal Presumably it would be fairly simple to see to that by calling clearTimeout(pressTimer) on mousemove, unless I'm missing something. Which admittedly would hardly be unprecendented. Commented Dec 19, 2013 at 5:19
  • 9
    @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!
    – Ian
    Commented Feb 18, 2015 at 12:44
  • 8
    Bear 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.
    – dartacus
    Commented Nov 2, 2016 at 12:49
  • 6
    Although 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.
    – user2895783
    Commented Mar 29, 2019 at 11:59
36

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; }
}
9
  • I 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...
    – Xander
    Commented Sep 1, 2015 at 14:52
  • @Xander: Maybe because the :hover state is sticky on touch devices, maybe that also applies here.
    – kelunik
    Commented Sep 1, 2015 at 15:03
  • Dang, 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!
    – Xander
    Commented Sep 1, 2015 at 15:10
  • @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.
    – kelunik
    Commented Sep 1, 2015 at 16:30
  • 1
    Figured 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.
    – Xander
    Commented Sep 1, 2015 at 16:32
27

You can use taphold event of jQuery mobile API.

jQuery("a").on("taphold", function( event ) { ... } )
1
26

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)

Demo

7
  • 2
    Owesome, mate !!
    – Jeff T.
    Commented Dec 5, 2018 at 8:48
  • 3
    This 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.
    – user2895783
    Commented Mar 29, 2019 at 14:16
  • 16
    It’s Open Source, feel free to contribute to the project :) Commented Mar 29, 2019 at 15:21
  • @JohnDoherty great! but can we still use "onClick" with the same element?
    – Devashish
    Commented Jun 9, 2019 at 7:02
  • 3
    You should still get the 'onclick' event so long as the long press is released before 'long-press-delay' timer kicks in Commented Jun 10, 2019 at 2:03
14

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.

2
  • 1
    The 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.
    – arlomedia
    Commented Nov 4, 2016 at 17:27
  • This fork contains the fix referenced by arlomedia github.com/jgarnet/Longclick/commit/…
    – Andy Gee
    Commented Jun 29, 2022 at 11:00
14

For modern, mobile browsers:

document.addEventListener('contextmenu', callback);

https://developer.mozilla.org/en-US/docs/Web/Events/contextmenu

4
  • Or for JQuery use $(selector).bind('contextmenu', function() {})
    – dfmiller
    Commented Apr 27, 2016 at 19:11
  • 2
    stop using bind() jquery 1.7+ = on() and unbind() = off()
    – dbinott
    Commented Jun 17, 2016 at 19:07
  • Or inline the HTML element: oncontextmenu="callback();" It's probably desirable to add e.g. event.preventDefault(); somewhere near the top of the callback function. Commented Aug 20, 2021 at 8:33
  • 1
    This event is not supported by iOS. Commented Dec 1, 2022 at 18:03
11

jQuery plugin. Just put $(expression).longClick(function() { <your code here> });. Second parameter is hold duration; default timeout is 500 ms.

(function($) {
    $.fn.longClick = function(callback, timeout) {
        var timer;
        timeout = timeout || 500;
        $(this).mousedown(function() {
            timer = setTimeout(function() { callback(); }, timeout);
            return false;
        });
        $(document).mouseup(function() {
            clearTimeout(timer);
            return false;
        });
    };

})(jQuery);
2
  • this is not retained in call. Commented Feb 24, 2015 at 15:48
  • hi Bro can we use it as a backbone event Commented Jul 8, 2015 at 10:30
7
$(document).ready(function () {
    var longpress = false;

    $("button").on('click', function () {
        (longpress) ? alert("Long Press") : alert("Short Press");
    });

    var startTime, endTime;
    $("button").on('mousedown', function () {
        startTime = new Date().getTime();
    });

    $("button").on('mouseup', function () {
        endTime = new Date().getTime();
        longpress = (endTime - startTime < 500) ? false : true;
    });
});

DEMO

3
  • 2
    Whit 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.
    – jedi
    Commented May 16, 2016 at 12:57
  • would this cover the case when a user started scrolling instead of finishing their longpress in the same spot?
    – Akin Hwan
    Commented May 31, 2019 at 13:06
  • @AkinHwan No it would only get triggered if the mouse click was released over the same element.
    – razz
    Commented May 31, 2019 at 18:21
5

For cross platform developers (Note All answers given so far will not work on iOS):

Mouseup/down seemed to work okay on android - but not all devices ie (samsung tab4). Did not work at all on iOS.

Further research its seems that this is due to the element having selection and the native magnification interupts the listener.

This event listener enables a thumbnail image to be opened in a bootstrap modal, if the user holds the image for 500ms.

It uses a responsive image class therefore showing a larger version of the image. This piece of code has been fully tested upon (iPad/Tab4/TabA/Galaxy4):

var pressTimer;  
$(".thumbnail").on('touchend', function (e) {
   clearTimeout(pressTimer);
}).on('touchstart', function (e) {
   var target = $(e.currentTarget);
   var imagePath = target.find('img').attr('src');
   var title = target.find('.myCaption:visible').first().text();
   $('#dds-modal-title').text(title);
   $('#dds-modal-img').attr('src', imagePath);
   // Set timeout
   pressTimer = window.setTimeout(function () {
      $('#dds-modal').modal('show');
   }, 500)
});
2
  • nice solution for iOS
    – eric xu
    Commented Jun 3, 2017 at 10:25
  • how 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
    Commented May 31, 2019 at 13:01
3

The Diodeus's answer is awesome, but it prevent you to add a onClick function, it'll never run hold function if you put an onclick. And the Razzak's answer is almost perfect, but it run hold function only on mouseup, and generally, the function runs even if user keep holding.

So, I joined both, and made this:

$(element).on('click', function () {
    if(longpress) { // if detect hold, stop onclick function
        return false;
    };
});

$(element).on('mousedown', function () {
    longpress = false; //longpress is false initially
    pressTimer = window.setTimeout(function(){
    // your code here

    longpress = true; //if run hold function, longpress is true
    },1000)
});

$(element).on('mouseup', function () {
    clearTimeout(pressTimer); //clear time on mouseup
});
1
  • what if user starting scrolling after mousedown, and wasn't intending to do a longpress
    – Akin Hwan
    Commented May 31, 2019 at 13:05
1

You could set the timeout for that element on mouse down and clear it on mouse up:

$("a").mousedown(function() {
    // set timeout for this element
    var timeout = window.setTimeout(function() { /* … */ }, 1234);
    $(this).mouseup(function() {
        // clear timeout for this element
        window.clearTimeout(timeout);
        // reset mouse up event handler
        $(this).unbind("mouseup");
        return false;
    });
    return false;
});

With this each element gets its own timeout.

2
  • 3
    $(this).mouseup(function(){}); does not remove the event handler, it adds another one. Use .unbind instead. Commented Apr 12, 2010 at 20:42
  • 1
    should use off() now instead of unbind.
    – dbinott
    Commented Jun 17, 2016 at 19:03
1

This worked for me:

const a = document.querySelector('a');

a.oncontextmenu = function() {
   console.log('south north');
};

https://developer.mozilla.org/docs/Web/API/GlobalEventHandlers/oncontextmenu

1
  • This worked in mobile. Perfect one Commented Nov 1, 2022 at 12:18
0

You can use jquery-mobile's taphold. Include the jquery-mobile.js and the following code will work fine

$(document).on("pagecreate","#pagename",function(){
  $("p").on("taphold",function(){
   $(this).hide(); //your code
  });    
});
1
  • This should be the accepted answer since jquery-mobile provides a good stable framework
    – pasx
    Commented Jul 30, 2015 at 5:17
0

Most elegant and clean is a jQuery plugin: https://github.com/untill/jquery.longclick/, also available as packacke: https://www.npmjs.com/package/jquery.longclick.

In short, you use it like so:

$( 'button').mayTriggerLongClicks().on( 'longClick', function() { your code here } );

The advantage of this plugin is that, in contrast to some of the other answers here, click events are still possible. Note also that a long click occurs, just like a long tap on a device, before mouseup. So, that's a feature.

0

I needed something for longpress keyboard events, so I wrote this.

var longpressKeys = [13];
var longpressTimeout = 1500;
var longpressActive = false;
var longpressFunc = null;

document.addEventListener('keydown', function(e) {
    if (longpressFunc == null && longpressKeys.indexOf(e.keyCode) > -1) {
        longpressFunc = setTimeout(function() {
            console.log('longpress triggered');
            longpressActive = true;
        }, longpressTimeout);

    // any key not defined as a longpress
    } else if (longpressKeys.indexOf(e.keyCode) == -1) {
        console.log('shortpress triggered');
    }
});

document.addEventListener('keyup', function(e) {
    clearTimeout(longpressFunc);
    longpressFunc = null;

    // longpress key triggered as a shortpress
    if (!longpressActive && longpressKeys.indexOf(e.keyCode) > -1) {
        console.log('shortpress triggered');
    }
    longpressActive = false;
});
0

In vanila JS if need to detect long-click after click released:

    document.addEventListener("mousedown", longClickHandler, true);
    document.addEventListener("mouseup", longClickHandler, true);

    let startClick = 0;
    function longClickHandler(e){   
      if(e.type == "mousedown"){
        startClick = e.timeStamp;
      }
      else if(e.type == "mouseup" && startClick > 0){
        if(e.timeStamp - startClick > 500){  // 0.5 secound
          console.log("Long click !!!");
        }
      }
    }

May need to use timer if need to check long-click while clicking. But for most case after release click is enought.

-1

For me it's work with that code (with jQuery):

var int       = null,
    fired     = false;

var longclickFilm = function($t) {
        $body.css('background', 'red');
    },
    clickFilm = function($t) {
        $t  = $t.clone(false, false);
        var $to = $('footer > div:first');
        $to.find('.empty').remove();
        $t.appendTo($to);
    },
    touchStartFilm = function(event) {
        event.preventDefault();
        fired     = false;
        int       = setTimeout(function($t) {
            longclickFilm($t);
            fired = true;
        }, 2000, $(this)); // 2 sec for long click ?
        return false;
    },
    touchEndFilm = function(event) {
        event.preventDefault();
        clearTimeout(int);
        if (fired) return false;
        else  clickFilm($(this));
        return false;
    };

$('ul#thelist .thumbBox')
    .live('mousedown touchstart', touchStartFilm)
    .live('mouseup touchend touchcancel', touchEndFilm);
-1

You can check the time to identify Click or Long Press [jQuery]

function AddButtonEventListener() {
try {
    var mousedowntime;
    var presstime;
    $("button[id$='" + buttonID + "']").mousedown(function() {
        var d = new Date();
        mousedowntime = d.getTime();
    });
    $("button[id$='" + buttonID + "']").mouseup(function() {
        var d = new Date();
        presstime = d.getTime() - mousedowntime;
        if (presstime > 999/*You can decide the time*/) {
            //Do_Action_Long_Press_Event();
        }
        else {
            //Do_Action_Click_Event();
        }
    });
}
catch (err) {
    alert(err.message);
}
} 
-1

You can use jquery Touch events. (see here)

  let holdBtn = $('#holdBtn')
  let holdDuration = 1000
  let holdTimer

  holdBtn.on('touchend', function () {
    // finish hold
  });
  holdBtn.on('touchstart', function () {
    // start hold
    holdTimer = setTimeout(function() {
      //action after certain time of hold
    }, holdDuration );
  });
-1

like this?

target.addEeventListener("touchstart", function(){
   // your code ...
}, false);    

Not the answer you're looking for? Browse other questions tagged or ask your own question.