I'm handling both the click and dblclick event on a DOM element. Each one carries out a different command, but I find that when double clicking on the element, in addition to firing the double click event, the click event is also fired twice. What is the best approach for preventing this behavior?
14 Answers
In case anyone else stumbles on this (as I did) looking for an answer, the absolute best solution that I could come up with is the following:
$node.on('click',function(e){
if(e.originalEvent.detail > 1){
return;
/* if you are returning a value from this
function then return false or cancel
the event some other way */
}
});
Done. If there is more than one click back to back, the second, third,etc. will not fire. I definitely prefer this to using any sort of timers.
I got myself pointed in this direction by reading this.
Incidentally: I was first researching this problem because I accidentally double clicked a paginated link, and the event fired and finished twice before the callback could happen.
Before coming up with the code above, I had
if e.originalEvent.detail === 2 //return
however, I was able to click on the link 3 times (a triple click), and though the second click didn't fire, the third did

- 3,877
- 5
- 34
- 47
-
3This would prevent the 2nd click from firing and still let the 1st click fire. The OP wanted to disable the 1st click if there is a 2nd click, if I understand correctly. I think the best bet is using a small delay (I'm using 200ms, but was hoping there was a better solution that I just couldn't see). – ClarkeyBoy Jul 01 '15 at 05:58
-
@ClarkeyBoy - you're incorrect. This will disable the first click if there is a second. Try it. – dgo Jul 15 '15 at 19:27
-
5Doesn't work in IE 11 x64 (Win8.1): event.detail = 0 always, either single click or double – robert4 Sep 19 '15 at 17:48
-
@robert4 As 12% still uses IE, that's too bad. But, this seems to work: `$node.on('click', function (e) { if (e.originalEvent.detail > 1 || alreadyClicked == true) { alreadyClicked = false; return; } alreadyClicked = true; //Code here. alreadyClicked = false; }` Of course, you'd have to declare the variable in the script-body and set it in a document.ready I know this question is old, but it still an issue. NB: edited to format & add the above sentence – NotImplementedException Apr 19 '18 at 15:38
-
@user1167442 thanks for the pointing out the right direction, my workaround isn't perfect but it's already a bit better than without it. Feel free to add this to your answer if you reckon it's a useful addition. – NotImplementedException Apr 19 '18 at 15:44
-
I love this. But - how can it be applied to tap/touch events? – Josh Carvin Nov 12 '18 at 16:32
-
@JoshCarvin - there are two answers: 1. For tap events on mobile devices, just use click - then it will be the same. If you want to allow zooming in, more info is here - https://stackoverflow.com/questions/46167604/ios-html-disable-double-tap-to-zoom. There is no native `touch` or `tap` events, but there is `touchstart`. You are probably much better off using `click`, but it may depend on your use case. – dgo Nov 12 '18 at 19:36
-
For anyone wanting to know why/how it works: [`originalEvent`](https://stackoverflow.com/questions/16674963/event-originalevent-jquery) is a jQuery property storing the original DOM event: a `UIEvent`. And so the [`detail`](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail) property is standard, "For click or dblclick events, UIEvent.detail is the current click count." – Fabien Snauwaert Jan 31 '19 at 09:47
-
5…but, as @ClarkeyBoy said, with this approach, a double will trigger first a click event where detail is 1, and then a second one where detail is 2. See [jsfiddle](https://jsfiddle.net/tsyrak/0y8uqemc/4/). So as far as I can tell this does not answer the OP. – Fabien Snauwaert Jan 31 '19 at 12:46
-
I agree with @FabienSnauwaert: what this technique does in my use case, is that it still fires-off click, but only on the second click of the double-click. And it does this on top of my double-click too! – Fabien Haddadi Jan 14 '21 at 23:12
-
1`e.originalEvent` is undefined – Rahul Nov 23 '21 at 19:33
-
@Rahul - show me some code. Better yet a jsfiddle reproducing the issue. Doesn’t seem possible – dgo Nov 27 '21 at 02:56
In a comment, you said,
I delay the click handler by 300 ms (a noticeable and annoying delay) and even ...
So it sounds like what you want is that when you click then the DOM should geneate a click event immediately, except not if the click is the first click of a double-click.
To implement this feature, when you click, the DOM would need to be able to predict whether this is the final click or whether it's the first of a double-click (however I don't think is possible in general for the DOM to predict whether the user is about to click again).
What are the two distinct actions which you're trying to take on click and double-click? IMO, in a normal application you might want both events: e.g. single-click to focus on an element and then double-click to activate it.
When you must separate the events, some applications use something other than double-click: for example, they use right-click, or control-click.

- 54,973
- 13
- 116
- 224
-
1Thanks for the updated answer. I think this really comes down to the fact that I need to rethink my UI. What I want to accomplish really isn't going to be possible. I should simply use two controls for the two actions, or use a modifier key instead of the double-click. Thanks! – David May 19 '09 at 13:29
You can use UIEvent.detail
if you want to detect how many times the element was clicked and fire events based on that.
A simple example:
element.addEventListener("click", function (e) {
if (e.detail === 1) {
// do something if the element was clicked once.
} else if (e.detail === 2) {
// do something else if the element was clicked twice
}
});

- 5,190
- 3
- 25
- 47

- 540
- 1
- 6
- 20
-
-
-
@remborg it's still supported https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail – tarek salem Jul 23 '22 at 12:53
In this case, it is best to delay the execution of the single click event slightly. Have your double click handler set a variable that the single click event will check. If that variable has a particular value, could be boolDoubleClick == true
, then don't fire/handle
the single click.

- 66,747
- 15
- 75
- 101

- 13,703
- 5
- 44
- 49
-
Actually, that's what I'm doing now, but it seems like it's a rather kludgy solution. I delay the click handler by 300 ms (a noticeable and annoying delay) and even with that you can still double click slow enough (eg. 350 ms) to make both of them fire. – David May 19 '09 at 02:19
-
Interesting. It isn't unreasonable to assume that if they delay too long for the second click that the desired effect would be 2 single clicks. – Jordan S. Jones May 19 '09 at 03:51
-
Unfortunately the double-click time is configurable by the end-user (e.g. using Control Panel/Mouse), and I suppose that JavaScript in a browser cannot get/determine what that time delay is configured as. – ChrisW May 19 '09 at 04:06
-
-
often you can change the delay of double click in the OS settings. On macOS for instance you can set this value to an insanely long time. Breaking any reasonable delay you would hard code. – Jespertheend Mar 29 '20 at 16:55
Thanks to all the other answers here as the combination of them seems to provide a reasonable solution for me when the interaction requires both, but mutually exclusive:
var pendingClick = 0;
function xorClick(e) {
// kill any pending single clicks
if (pendingClick) {
clearTimeout(pendingClick);
pendingClick = 0;
}
switch (e.detail) {
case 1:
pendingClick = setTimeout(function() {
console.log('single click action here');
}, 500);// should match OS multi-click speed
break;
case 2:
console.log('double click action here');
break;
default:
console.log('higher multi-click actions can be added as needed');
break;
}
}
myElem.addEventListener('click', xorClick, false);
Update: I added a generalized version of this approach along with a click polyfill for touch devices to this Github repo with examples:

- 17,359
- 16
- 83
- 116
AFAIK DOM Level 2 Events makes no specification for double-click. It doesn't work for me on IE7 (there's a shock), but FF and Opera have no problem managing the spec, where I can attach all actions to the click event, but for double-click just wait till the "detail" attribute of the event object is 2. From the docs: "If multiple clicks occur at the same screen location, the sequence repeats with the detail attribute incrementing with each repetition."
-
This is actually a very elegant solution to the problem. It still requires a setTimout/clearTimeout combo for the first click but it simplifies coordination between the two and even opens the door for triple-clicks, etc. Thanks! – mckamey Jun 15 '12 at 17:58
Here is what I did to distinguish within a module
node.on('click', function(e) {
//Prepare for double click, continue to clickHandler doesn't come soon enough
console.log("cleared timeout in click",_this.clickTimeout);
clearTimeout(_this.clickTimeout);
_this.clickTimeout = setTimeout(function(){
console.log("handling click");
_this.onClick(e);
},200);
console.log(_this.clickTimeout);
});
node.on('dblclick', function (e) {
console.log("cleared timeout in dblclick",_this.clickTimeout);
clearTimeout(_this.clickTimeout);
// Rest of the handler function

- 91
- 1
- 2
I use this solution for my project to prevent click event action, if I had dblclick event that should do different thing.
Note: this solution is just for click and dblclick and not any other thing like tripleclick or etc.
To see proper time between click and double click see this
sorry for my bad English. I hope it helps :)
var button, isDblclick, timeoutTiming;
var clickTimeout, dblclickTimeout;
//-----
button = $('#button');
isDblclick = false;
/*
the proper time between click and dblclick is not standardized,
and is cutsomizable by user apparently (but this is windows standard I guess!)
*/
timeoutTiming = 500;
//-----
button.on('dblclick', function () {
isDblclick = true;
clearTimeout(dblclickTimeout);
dblclickTimeout = setTimeout(function () {
isDblclick = false;
}, timeoutTiming);
//-----
// here goes your dblclick codes
console.log('double clicked! not click.');
}).on('click', function () {
clearTimeout(clickTimeout);
clickTimeout = setTimeout(function () {
if(!isDblclick) {
// here goes your click codes
console.log('a simple click.');
}
}, timeoutTiming);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" id="button">
click/dblclick on this to see the result
</button>

- 465
- 3
- 11
-
Seems excessive to require 7,265 lines of additional JS to perform this one function. – Reggie Pinkham Aug 11 '22 at 03:04
-
@ReggiePinkham I know, please use `addEventListener` instead if you don't use other functionality of `jQuery` – MMDM Sep 13 '22 at 16:44
It can be achieved via following code
var clickHandler = function(e) { /* put click event handling code here */ };
var doubleclickHandler = function(e) { /* put doubleclick event handling code here */ }
const maxMsBetweenClicks = 300;
var clickTimeoutId = null;
document.addEventListener("dblclick", handleDoubleClick);
document.addEventListener("click", handleSingleClick);
function handleSingleClick(e){
clearTimeout(clickTimeoutId);
clickTimeoutId = setTimeout( function() { clickHandler(e);}, maxMsBetweenClicks);
}
function handleDoubleClick(e){
clearTimeout(clickTimeoutId);
doubleclickHandler(e);
}

- 11,985
- 4
- 38
- 36

- 21
- 2
I know this is old as heck, but thought I'd post anyhow since I just ran into the same problem. Here's how I resolved it.
$('#alerts-display, #object-display').on('click', ['.item-data-summary', '.item-marker'], function(e) {
e.preventDefault();
var id;
id = setTimeout(() => {
// code to run here
return false;
}, 150);
timeoutIDForDoubleClick.push(id);
});
$('.panel-items-set-marker-view').on('dblclick', ['.summary', '.marker'], function(e) {
for (let i = 0; i < timeoutIDForDoubleClick.length; i++) {
clearTimeout(timeoutIDForDoubleClick[i]);
}
// code to run on double click
e.preventDefault();
});

- 1,187
- 2
- 9
- 21
Here is my simple solution to prevent the second click. Of course, I could restart the timeout when a double click detected, but in reality I never need it.
clickTimeoutId = null;
onClick(e) {
if (clickTimeoutId !== null) {
// Double click, do nothing
return;
}
// Single click
// TODO smth
clickTimeoutId = setTimeout(() => {
clearTimeout(clickTimeoutId);
clickTimeoutId = null;
}, 300);
}

- 1
- 1
Summarizing, to recognize the simpleClick and doubleClick events on the same element, just treat the onClick event with this method:
var EVENT_DOUBLE_CLICK_DELAY = 220; // Adjust max delay btw two clicks (ms)
var eventClickPending = 0;
function onClick(e){
if ((e.detail == 2 ) && (eventClickPending!= 0)) {
// console.log('double click action here ' + e.detail);
clearTimeout(eventClickPending);
eventClickPending = 0;
// call your double click method
fncEventDblclick(e);
} else if ((e.detail === 1 ) && (eventClickPending== 0)){
// console.log('sigle click action here 1');
eventClickPending= setTimeout(function() {
// console.log('Executing sigle click');
eventClickPending = 0
// call your single click method
fncEventClick(e);
}, EVENT_DOUBLE_CLICK_DELAY);
// } else { // do nothing
// console.log('more than two clicks action here ' + e.detail);
}
}

- 254
- 2
- 4
You can use debounce to free the single click handler from detecting the double/multiple clicks
Test at: https://jsfiddle.net/L3sajybp/
HTML
<div id='toDetect'>
Click or double-click me
</div>
<hr/>
<ol id='info'>
</ol>
JS
function debounce(func, wait, immediate) {
let timeout;
return function () {
const context = this,
args = arguments;
const later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
function debounceSingleClickOnly(func, timeout = 500) {
function eventHandler (event) {
const { detail } = event;
if (detail > 1) {
console.log('no double click for you '+ func.name);
console.log('');
return;
}
func.apply(this, arguments);
}
return debounce(eventHandler, timeout);
}
window.toDetect.addEventListener('click', debounceSingleClickOnly(handleSingleClick));
window.toDetect.addEventListener('dblclick', handleDoubleClick);
function handleS() {
console.log('S func');
console.log(this.id);
}
function handleSingleClick(event) {
console.log('single click');
const divText = document.createElement('li');
divText.appendChild(document.createTextNode('single click'));
window.info.appendChild(divText)
console.group();
console.log('this element was single-clicked: ' + event.target.id);
console.log(this.id);
console.log('');
console.groupEnd();
}
function handleDoubleClick(event) {
console.log('double click');
const divText = document.createElement('li');
divText.appendChild(document.createTextNode('double click'));
window.info.appendChild(divText);
console.group();
console.log('this element was double-clicked: ' + event.target.id);
console.log(this.id);
console.log('');
console.groupEnd();
}

- 38,643
- 9
- 94
- 118
const toggle = () => {
watchDouble += 1;
setTimeout(()=>{
if (watchDouble === 2) {
console.log('double' + watchDouble)
} else if (watchDouble === 1) {
console.log("signle" + watchDouble)
}
watchDouble = 0
},200);
}

- 1
- 3
-
1While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Austen Holland May 28 '19 at 17:43