363

I'm handling the dblclick event on a span in my web app. A side effect of a double click is that it selects text on the page. How can I prevent this selection from happening?

mfluehr
  • 2,832
  • 2
  • 23
  • 31
David
  • 7,487
  • 6
  • 32
  • 25
  • Obviously depends on use-case, but likely best to turn your span into a button, **not selecting text on double-click is the default with buttons**, and also good for accessibility when a click performs a function. – James William Jul 10 '23 at 10:15

14 Answers14

403
function clearSelection() {
    if(document.selection && document.selection.empty) {
        document.selection.empty();
    } else if(window.getSelection) {
        var sel = window.getSelection();
        sel.removeAllRanges();
    }
}

You can also apply these styles to the span for all non-IE browsers and IE10:

span.no_selection {
    user-select: none; /* standard syntax */
    -webkit-user-select: none; /* webkit (safari, chrome) browsers */
    -moz-user-select: none; /* mozilla browsers */
    -khtml-user-select: none; /* webkit (konqueror) browsers */
    -ms-user-select: none; /* IE10+ */
}
Jay Sullivan
  • 17,332
  • 11
  • 62
  • 86
Paolo Bergantino
  • 480,997
  • 81
  • 517
  • 436
  • 52
    Is there any way to actually prevent selection as opposed to removing the selection after the fact? Also, your second if statement could be inside the else if for better readability. – David May 19 '09 at 01:07
  • The CSS looks great! Any idea if there's something similar available for IE? – David May 19 '09 at 01:12
  • Sorry about the mess with the braces; I grabbed that code from another site without checking. Fixed. There's no IE equivalent, I'm afraid. – Paolo Bergantino May 19 '09 at 01:13
  • 8
    Best to use -webkit- prefix (this is the preferred prefix for Webkit based browsers) in addition to -moz- (and -khtml- if you have a large Konqueror audience). – eyelidlessness Oct 14 '09 at 20:37
  • 3
    This is now available in IE10 as `-ms-user-select: none;` see http://blogs.msdn.com/b/ie/archive/2012/01/11/controlling-selection-with-css-user-select.aspx @PaoloBergantino – dukevin Jun 21 '12 at 08:38
  • The event-binding approach (at the the time of this writing, the Using Jquery answer below) is the better approach. – Tim Harper Aug 30 '12 at 17:51
  • 1
    @TimHarper: As far as Javascript solutions using a library, sure. Not really sure why that warrants a downvote. – Paolo Bergantino Aug 30 '12 at 18:01
  • 1
    Sorry Paolo, I thought this was a jQuery question, but on second glance I was clearly wrong. Looks like I was penalized for my downvote... rightly so. My mistake. – Tim Harper Oct 25 '12 at 23:49
  • There is also an -me-user-select: none property for Internet Explorer. https://developer.mozilla.org/en/docs/CSS/user-select – Jan Aagaard May 10 '13 at 14:38
  • i named my style `.unselectable` after the html attribute `unselectable="on"` which does not seem to be effective anymore. – Valamas Jun 27 '13 at 07:56
  • Warning: using "user-select:none" causes several focus issues if also using divs with "contenteditable=true" – steph643 Dec 01 '14 at 20:45
  • 24
    There is a difference between disabling selection on double click and disabling it completely. The first increases usability. The second decreases. – Robo Robok Feb 22 '15 at 22:53
  • @RoboRobok I faced that problem. I have a list where you can collapse sub-items by double-clicking, and I wanted to prevent text selection on double click, but not when the user drags across. My solution ended up being removing the current selection from the double click handler. I also thought about returning false from the mouse down just before a double-click, but that ended up being trickier than I was willing to invest the time. – Ruan Mendes Mar 09 '15 at 17:19
  • 1
    @JuanMendes I ended up with `user-select: none` styles (plus all prefixes) on `a:active` selector. It works good, selection by dragging will still work, because dragging makes the active link (if there's any) inactive. – Robo Robok Mar 12 '15 at 02:05
  • I might be wrong here, but this would disable all ability to select text? Not just preventing a clickable element from being highlighten as selected when the user clicks a custom click event element twice? I still want the user to be able to select my text via click and drag, – ThorSummoner Mar 13 '15 at 18:35
  • !!!! THE CSS SOLUTION PROVIDED IS NOT RECOMMENDED. https://developer.mozilla.org/en-US/docs/Web/CSS/user-select Presently user-select is not on the standards track and should be avoided! – dudewad Aug 27 '15 at 23:38
  • THIS DOES NOT WORK (the javascript solution). At least, not if called from inside the event handler that handles the double click, which is the only place where it would be of any use. – matteo Sep 01 '15 at 16:02
  • This answer is missing where clearSelection() would get called. Here you go add to answer if you want: $('#myElement').on('mousedown', function() { clearSelection(); }) – Andrew Jan 17 '18 at 02:48
  • Chrome selects text in next text element if you dclick on a preceeding div.. ..which then messes up subsequent mousemove/down behaviour on the div - clearing the selection fixes it ( log any dclick on the div and clear selections if mousemove/down on it later while logged dclick uncorrected ) – Bob Jan 15 '19 at 18:38
  • 2
    @dudewad in fact (at this time) it is in fact on a standards track ([CSS Basic User Interface Module Level 4](https://drafts.csswg.org/css-ui-4/#propdef-user-select)). I realize this has probably changed since you posted your comment, but for completeness, thought it worth mentioning. – Kirk Woll Jul 13 '19 at 01:27
148

To prevent text selection ONLY after a double click:

You could use MouseEvent#detail property. For mousedown or mouseup events, it is 1 plus the current click count.

document.addEventListener('mousedown', function(event) {
  if (event.detail > 1) {
    event.preventDefault();
    // of course, you still do not know what you prevent here...
    // You could also check event.ctrlKey/event.shiftKey/event.altKey
    // to not prevent something useful.
  }
}, false);
Some dummy text

See https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail

vsync
  • 118,978
  • 58
  • 307
  • 400
4esn0k
  • 9,789
  • 7
  • 33
  • 40
124

In plain javascript:

element.addEventListener('mousedown', function(e){ e.preventDefault(); }, false);

Or with jQuery:

jQuery(element).mousedown(function(e){ e.preventDefault(); });
fregante
  • 29,050
  • 14
  • 119
  • 159
Tom
  • 1,265
  • 1
  • 8
  • 2
  • 26
    Yep, I used this to solve the same problem I was having (+1), except instead of `return false` used `event.preventDefault()` which doesn't kill any other handlers you might have on mousedown. – Simon East Feb 24 '12 at 03:16
  • 2
    This breaks textarea elements on the page :( – john k Jan 09 '15 at 02:35
  • 1
    @johnktejik only if `element` is a textarea, yes. – fregante Apr 14 '15 at 11:48
  • 14
    Would expect to have this event handler assigned to "dblclick" – but that does not work, which is so weird. With "mousedown", you are of course also prevented from selecting text by dragging. – corwin.amber Mar 31 '16 at 16:48
65

FWIW, I set user-select: none to the parent element of those child elements that I don't want somehow selected when double clicking anywhere on the parent element. And it works! Cool thing is contenteditable="true", text selection and etc. still works on the child elements!

So like:

<div style="user-select: none">
  <p>haha</p>
  <p>haha</p>
  <p>haha</p>
  <p>haha</p>
</div>
kyw
  • 6,685
  • 8
  • 47
  • 59
10

A simple Javascript function that makes the content inside a page-element unselectable:

function makeUnselectable(elem) {
  if (typeof(elem) == 'string')
    elem = document.getElementById(elem);
  if (elem) {
    elem.onselectstart = function() { return false; };
    elem.style.MozUserSelect = "none";
    elem.style.KhtmlUserSelect = "none";
    elem.unselectable = "on";
  }
}
10

For those looking for a solution for Angular 2+.

You can use the mousedown output of the table cell.

<td *ngFor="..."
    (mousedown)="onMouseDown($event)"
    (dblclick) ="onDblClick($event)">
  ...
</td>

And prevent if the detail > 1.

public onMouseDown(mouseEvent: MouseEvent) {
  // prevent text selection for dbl clicks.
  if (mouseEvent.detail > 1) mouseEvent.preventDefault();
}

public onDblClick(mouseEvent: MouseEvent) {
 // todo: do what you really want to do ...
}

The dblclick output continues to work as expected.

bvdb
  • 22,839
  • 10
  • 110
  • 123
3

If you are trying to completely prevent selecting text by any method as well as on a double click only, you can use the user-select: none css attribute. I have tested in Chrome 68, but according to https://caniuse.com/#search=user-select it should work in the other current normal user browsers.

Behaviorally, in Chrome 68 it is inherited by child elements, and did not allow selecting an element's contained text even if when text surrounding and including the element was selected.

stackuser83
  • 2,012
  • 1
  • 24
  • 41
2

If you are using Vue JS, just append @mousedown.prevent="" to your element and it is magically going to disappear !

1

or, on mozilla:

document.body.onselectstart = function() { return false; } // Or any html object

On IE,

document.body.onmousedown = function() { return false; } // valid for any html object as well
José Leal
  • 7,989
  • 9
  • 35
  • 54
0

To prevent IE 8 CTRL and SHIFT click text selection on individual element

var obj = document.createElement("DIV");
obj.onselectstart = function(){
  return false;
}

To prevent text selection on document

window.onload = function(){
  document.onselectstart = function(){
    return false;
  }
}
rajesh
  • 382
  • 4
  • 5
0

Old thread, but I came up with a solution that I believe is cleaner since it does not disable every even bound to the object, and only prevent random and unwanted text selections on the page. It is straightforward, and works well for me. Here is an example; I want to prevent text-selection when I click several time on the object with the class "arrow-right":

$(".arrow-right").hover(function(){$('body').css({userSelect: "none"});}, function(){$('body').css({userSelect: "auto"});});

HTH !

nncho
  • 165
  • 7
0

I know this is an old question but it is still perfectly valid in 2021. However, what I'm missing in terms of answers is any mentioning of Event.stopPropagation().

The OP is asking for the dblclick event but from what I see the same problem occurs with the pointerdown event. In my code I register a listener as follows:

this.addEventListener("pointerdown", this._pointerDownHandler.bind(this));

The listener code looks as follows:

_pointerDownHandler(event) {
  // Stuff that needs to be done whenever a click occurs on the element
}

Clicking fast multiple times on my element gets interpreted by the browser as double click. Depending on where your element is located on the page that double click will select text because that is the given behavior.

You could disable that default action by invoking Event.preventDefault() in the listener which does solve the problem, at least in a way.

However, if you register a listener on an element and write the corresponding "handling" code you might as well swallow that event which is what Event.stopPropagation() ensures. Therefore, the handler would look as follows:

_pointerDownHandler(event) {
  event.stopPropagation();
  // Stuff that needs to be done whenever a click occurs on the element
}

Because the event has been consumed by my element, elements further up the hierarchy are not aware of that event and won't execute their handling code.

If you let the event bubble up, elements higher in the hierarchy would all execute their handling code but are be told to not do so by Event.preventDefault() which makes less sense to me than preventing the event from bubbling up in the first place.

ackh
  • 1,648
  • 2
  • 18
  • 36
0

Tailwind CSS:

<div class="select-none ...">
  This text is not selectable
</div>
John Smith
  • 1,726
  • 2
  • 18
  • 30
-5

I had the same problem. I solved it by switching to <a> and add onclick="return false;" (so that clicking on it won't add a new entry to browser history).

minhle_r7
  • 771
  • 9
  • 20