59

I'm implementing item selection functionality in javascript (using jQuery). item is a li that contains some html.
the user can click on one item (makes it selected) and then shift-click on another item to select all the items in between. this basically works OK, however the shift-click also selects (higtlights) the text that appears inside the items (the basic browser functionality for shift clicks). is there any way to disable this?

Asaf David
  • 3,583
  • 3
  • 29
  • 33

6 Answers6

63

Try this after the Shift + click...

document.getSelection().removeAllRanges();

If that is not effective enough, you might have to also cancel the onselectstart event...

window.onload = function() {
  document.onselectstart = function() {
    return false;
  }
}
Josh Stodola
  • 81,538
  • 47
  • 180
  • 227
51

Try a combo of JavaScript and css to prevent the selection in the first place:

$('li').attr('unselectable', 'on'); // IE

css (for browsers not IE):

li {
            user-select: none; /* CSS3 (little to no support) */
        -ms-user-select: none; /* IE 10+ */
       -moz-user-select: none; /* Gecko (Firefox) */
    -webkit-user-select: none; /* Webkit (Safari, Chrome) */
}
typeoneerror
  • 55,990
  • 32
  • 132
  • 223
Roatin Marth
  • 23,589
  • 3
  • 51
  • 55
  • Note that the unselectable="on" has to be on all children nodes as well (eg div, p). Even a checkbox widget can be shift-clicked. – Curtis Yallop Apr 16 '14 at 18:39
  • This does not address the "while pressing shift" part. See @Anthony Mills answer for that. – ahlexander Jan 16 '18 at 09:26
  • 1
    As of today, unprefixed `user-select: none` covers 63% of all users while when prefixed, it covers 89% of users. https://caniuse.com/#feat=user-select-none – shreyasminocha Jan 11 '19 at 10:05
38

I have an application like that. Trick is, I wanted to allow selection, but I also wanted Ctrl-click and Shift-click for selecting items.

What I found was that everyone but IE allows you to beat this by canceling the mousedown event, and in IE what works best is to temporarily disable onselectstart:

$("#id").mousedown(function (e) {
    if (e.ctrlKey || e.shiftKey) {
        // For non-IE browsers
        e.preventDefault();

        // For IE
        if ($.support.msie) {
            this.onselectstart = function () { return false; };
            var me = this;  // capture in a closure
            window.setTimeout(function () { me.onselectstart = null; }, 0);
        }
    }
});
Jason
  • 105
  • 13
Anthony Mills
  • 8,676
  • 4
  • 32
  • 51
  • 2
    This was the secret I was searching for. On Chrome get momentary flash of selection, and on Safari also needed to add `document.getSelection().removeAllRanges();` – prototype Jun 21 '14 at 02:43
  • Hmmm, this works, but can also cause unexpected behavior. For example, the previously focused element stays in focus if you prevent default on the mousedown, instead of the focus shifting to the element clicked. – Skeets Sep 29 '21 at 04:19
  • Oh, but there's an easy fix... add this after the `preventDefault()`: `$(":focus").blur(); $(this).focus();` – Skeets Sep 29 '21 at 04:20
13

This code will stop text selection only during the "shift" key pressed, if you release it then you can select text as usual. Currently I'm using this es6 code.

["keyup","keydown"].forEach((event) => {
    window.addEventListener(event, (e) => {
        document.onselectstart = function() {
            return !(e.key == "Shift" && e.shiftKey);
        }
    });
});
Rubanraj Ravichandran
  • 1,213
  • 2
  • 17
  • 26
6

If you have checkboxes in your table rows (items), you can simply set focus to the checkbox for the row once you've made the selection. Focusing on the checkbox should get rid of the browser selection. You can also focus on a textbox or other form element. For JQuery,

$('tr').bind('click', function(e) {
  // If shift key was down when the row was clicked
  if (e.shiftKey) { 
    // Make the row selected
    $(this).parent().children().slice($(last).index(), $(this).index()+1).addClass('selected').find('input:checkbox').attr('checked', true);

    // Now focus on the checkbox within the row
    $('input:checkbox', $(this)).focus();
  }
});
Ray Perea
  • 5,640
  • 1
  • 35
  • 38
0

I've added a class to body then prevent default on mousedown event if the shift key was pressed.

      <body class="noselection">
    <script>
    $(document).ready(function() {
        $(".noselection").mousedown(function (e) {
        if (e.shiftKey) {
            
            e.preventDefault();
    
        }
    });
    });
</script>
lisandro
  • 454
  • 4
  • 12