165

How to highlight/select the contents of a DIV tag when the user clicks on the DIV...the idea is that all of the text is highlighted/selected so the user doesn't need to manually highlight the text with the mouse and potentially miss a bit of the text?

For example, say we've got a DIV as below:

<div id="selectable">http://example.com/page.htm</div>

...and when the user clicks on any of that URL the whole URL text is highlighted so they can easily drag the selected text around in the browser, or copy the complete URL with a right click.

Thanks!

Rick Davies
  • 713
  • 9
  • 22
Acyra
  • 15,864
  • 15
  • 46
  • 53

15 Answers15

220

function selectText(containerid) {
    if (document.selection) { // IE
        var range = document.body.createTextRange();
        range.moveToElementText(document.getElementById(containerid));
        range.select();
    } else if (window.getSelection) {
        var range = document.createRange();
        range.selectNode(document.getElementById(containerid));
        window.getSelection().removeAllRanges();
        window.getSelection().addRange(range);
    }
}
<div id="selectable" onclick="selectText('selectable')">http://example.com/page.htm</div>

Now you have to pass the ID as an argument, which in this case is "selectable", but it's more global, allowing you to use it anywhere multiple times without using, as chiborg mentioned, jQuery.

Dominic
  • 62,658
  • 20
  • 139
  • 163
Denis Sadowski
  • 3,035
  • 5
  • 24
  • 26
  • 8
    BTW, you can easily turn this into a jQuery click event handler replacing `document.getElementById('selectable')` with `this`. Then you can add the functionality unobtrusively to several elements, for example several divs in a container: `jQuery('#selectcontainer div').click(selectText);` – chiborg Oct 16 '11 at 09:57
  • @DenisSadowski's solution doesn't trigger `$.bind("copy",function(){});` :-( – Petja Jul 04 '13 at 20:00
  • 4
    This works fine on Chrome, FF, Safari (Mac) and Chrome and IE (Windows 9+, 8 not tested). But it does not seem to work on Safari on iPad Mini (iOS6) or iPhone 4, not sure about other iOS or Android. – prototype Dec 09 '13 at 02:52
  • 1
    Per this article, the query `if (window.getSelection) {` should come first for Opera (http://www.quirksmode.org/dom/range_intro.html) – prototype Dec 09 '13 at 03:23
  • 1
    This solution seems not to work in ie11. Any idea why? – Swiss Mister Nov 03 '14 at 16:40
  • 5
    In Chrome version 36+ this will return an error "Discontiguous selection is not supported". The solution is to add `window.getSelection().removeAllRanges();` before `window.getSelection().addRange(range);` – nHaskins Jan 26 '15 at 18:38
  • I found that this was selecting the text, but also invisible overflow on the right side. I solved this by appending `.firstChild` to the document.getElementById calls: `range.selectNode(document.getElementById(containerid).firstChild);` , which gets the text node. – Alex Beals Sep 24 '17 at 04:03
  • CSS4 solution is very clean and elegant. somone posted this solution below on this page. `.selectable{ -webkit-touch-callout: all; /* iOS Safari */ -webkit-user-select: all; /* Safari */ -khtml-user-select: all; /* Konqueror HTML */ -moz-user-select: all; /* Firefox */ -ms-user-select: all; /* Internet Explorer/Edge */ user-select: all; /* Chrome and Opera */ }` – Atif Saddique May 29 '18 at 18:10
156

UPDATE 2017:

To select the node's contents call:

window.getSelection().selectAllChildren(
    document.getElementById(id)
);

This works on all modern browsers including IE9+ (in standards mode).

Runnable Example:

function select(id) {
  window.getSelection()
    .selectAllChildren(
      document.getElementById("target-div") 
    );
}
#outer-div  { padding: 1rem; background-color: #fff0f0; }
#target-div { padding: 1rem; background-color: #f0fff0; }
button      { margin: 1rem; }
<div id="outer-div">
  <div id="target-div">
    Some content for the 
    <br>Target DIV
  </div>
</div>

<button onclick="select(id);">Click to SELECT Contents of #target-div</button>

The original answer below is obsolete since window.getSelection().addRange(range); has been deprecated

Original Answer:

All of the examples above use:

    var range = document.createRange();
    range.selectNode( ... );

but the problem with that is that it selects the Node itself including the DIV tag etc.

To select the Node's text as per the OP question you need to call instead:

    range.selectNodeContents( ... )

So the full snippet would be:

    function selectText( containerid ) {

        var node = document.getElementById( containerid );

        if ( document.selection ) {
            var range = document.body.createTextRange();
            range.moveToElementText( node  );
            range.select();
        } else if ( window.getSelection ) {
            var range = document.createRange();
            range.selectNodeContents( node );
            window.getSelection().removeAllRanges();
            window.getSelection().addRange( range );
        }
    }
isapir
  • 21,295
  • 13
  • 115
  • 116
71

There is pure CSS4 solution:

.selectable{
    -webkit-touch-callout: all; /* iOS Safari */
    -webkit-user-select: all; /* Safari */
    -khtml-user-select: all; /* Konqueror HTML */
    -moz-user-select: all; /* Firefox */
    -ms-user-select: all; /* Internet Explorer/Edge */
    user-select: all; /* Chrome and Opera */

}

user-select is a CSS Module Level 4 specification, that is currently a draft and non-standard CSS property, but browsers support it well — see #search=user-select.

.selectable{
    -webkit-touch-callout: all; /* iOS Safari */
    -webkit-user-select: all; /* Safari */
    -khtml-user-select: all; /* Konqueror HTML */
    -moz-user-select: all; /* Firefox */
    -ms-user-select: all; /* Internet Explorer/Edge */
    user-select: all; /* Chrome and Opera */

}
<div class="selectable">
click and all this will be selected
</div>

Read more on user-select here on MDN and play with it here in w3scools

gman
  • 100,619
  • 31
  • 269
  • 393
Mino
  • 973
  • 7
  • 14
  • 4
    +1 awesome awesome elegant solution! Tested Sept 2017 and it works flawlessly on FireFox and Chrome **BUT NOT IN MICROSOFT EDGE!?** Any ideas why not and how to fix that? thanks! – Sam Sep 18 '17 at 09:09
  • 1
    Mino, thanks this worked! One click selects the whole element. However it makes it impossible to swipe-select a subset of the text. . . . Did you possibly mean `-webkit-touch-callout: none;`? I'm getting a warning for `all`. Anyway, what is that setting doing here? . . . @Sam in 2020 I'm seeing `user-select` work on MS Edge. Saner heads may have prevailed. – Bob Stein Aug 25 '20 at 18:55
13

The answer of Neuroxik was really helpful. I had only a trouble with Chrome, because when I clicked on an external div, It did not work. I could solve it removing the old ranges before add the new range:

function selectText(containerid) {
    if (document.selection) {
        var range = document.body.createTextRange();
        range.moveToElementText(document.getElementById(containerid));
        range.select();
    } else if (window.getSelection()) {
        var range = document.createRange();
        range.selectNode(document.getElementById(containerid));
        window.getSelection().removeAllRanges();
        window.getSelection().addRange(range);
    }
}
<div id="selectable" onclick="selectText('selectable')">http://example.com/page.htm</div>
Josillo Debian
  • 131
  • 1
  • 3
11

For content editable stuff (not regular inputs, you need to use selectNodeContents (rather than just selectNode).

NOTE: All the references to "document.selection" and "createTextRange()" are for IE 8 and lower... You'll not likely need to support that monster if you're attempting to do tricky stuff like this.

function selectElemText(elem) {

    //Create a range (a range is a like the selection but invisible)
    var range = document.createRange();

    // Select the entire contents of the element
    range.selectNodeContents(elem);

    // Don't select, just positioning caret:
    // In front 
    // range.collapse();
    // Behind:
    // range.collapse(false);

    // Get the selection object
    var selection = window.getSelection();

    // Remove any current selections
    selection.removeAllRanges();

    // Make the range you have just created the visible selection
    selection.addRange(range);

}
bob
  • 7,539
  • 2
  • 46
  • 42
6

Using a text area field, you could use this: (Via Google)

<form name="select_all">

    <textarea name="text_area" rows="10" cols="80" 
    onClick="javascript:this.form.text_area.focus();this.form.text_area.select();">

    Text Goes Here 

    </textarea>
</form>

This is how I see most websites do it. They just style it with CSS so it doesn't look like a textarea.

Tyler Carter
  • 60,743
  • 20
  • 130
  • 150
5

This snippet provides the functionality you require. What you need to do is add an event to that div that which activates fnSelect in it. A quick hack that you totally shouldn't do and possibly might not work, would look like this:

document.getElementById("selectable").onclick(function(){
    fnSelect("selectable");
});

Obviously assuming that the linked to snippet had been included.

Simon Scarfe
  • 9,378
  • 4
  • 28
  • 32
5

I found it useful to wrap this function as a jQuery plugin:

$.fn.selectText = function () {
    return $(this).each(function (index, el) {
        if (document.selection) {
            var range = document.body.createTextRange();
            range.moveToElementText(el);
            range.select();
        } else if (window.getSelection) {
            var range = document.createRange();
            range.selectNode(el);
            window.getSelection().addRange(range);
        }
    });
}

So, it becomes a reusable solution. Then you can do this:

<div onclick="$(this).selectText()">http://example.com/page.htm</div>

And it will selected test in the div.

vitmalina
  • 1,829
  • 1
  • 14
  • 7
  • 1
    Remember to call window.getSelection().removeAllRanges(); as in Josillo's code. Also: I would advocate putting window.getSelect as the first option, since this is the HTML5 standard and document.selection is the old IE fallback for IE8 and earlier. – Jan Aagaard Apr 29 '14 at 07:43
3

How about this simple solution? :)

<input style="background-color:white; border:1px white solid;" onclick="this.select();" id="selectable" value="http://example.com/page.htm">

Sure it is not div-construction, like you mentioned, but still it is worked for me.

Niko Lay
  • 31
  • 1
  • 1
    Concise solution, but this doesn't account for text in an element other than an input or textarea field. – JoePC Jun 07 '18 at 21:11
3

Niko Lay: How about this simple solution? :)

`<input style="background-color:white; border:1px white solid;" onclick="this.select();" id="selectable" value="http://example.com/page.htm">`

.....

Code before:

<textarea rows="20" class="codearea" style="padding:5px;" readonly="readonly">

Code after:

<textarea rows="20" class="codearea" style="padding:5px;" readonly="readonly" onclick="this.select();" id="selectable">

Just this part onclick="this.select();" id="selectable" in my code worked fine. Selects all in my code box with one mouse click.

Thanks for help Niko Lay!

Igor B.
  • 71
  • 4
3

Easily achieved with the css property user-select set to all. Like this:

div.anyClass {
  user-select: all;
}
tirmey
  • 356
  • 4
  • 13
3

try this, altn adding to oncontextmenu will gice quick access to extentions allowing input this way.

<div onclick='window.getSelection().selectAllChildren(this)' id="selectable">http://example.com/page.htm</div>
Tue Barfod
  • 31
  • 1
1

A solution, working also in case your element is part of an iframe

element.ownerDocument?.getSelection()?.selectAllChildren(element);
Yoz
  • 707
  • 6
  • 20
0
$.fn.selectText = function () {
    return $(this).each(function (index, el) {
        if (document.selection) {
            var range = document.body.createTextRange();
            range.moveToElementText(el);
            range.select();
        } else if (window.getSelection) {
            var range = document.createRange();
            range.selectNode(el);
            window.getSelection().addRange(range);
        }
    });
}

Above answer is not working in Chrome because addRange remove previous added range. I didnt find any solution for this beside fake selection with css.

  • For someone this code may be helpful as I have tested & found it working in latest version of Chrome: $.fn.selectText = function () { return $(this).each(function (index, el) { if (document.selection) { var range = document.body.createTextRange(); range.moveToElementText(el); range.select(); } else if (window.getSelection) { var range = document.createRange(); range.selectNode(el); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); } }); } – Haider Abbas Jul 10 '17 at 15:32
0
export const selectText = (containerId) => {
  let selection = window.getSelection()
  let myElement = document.getElementById(containerId)

  if (selection.rangeCount > 0) {
    selection.removeAllRanges()
  }

  let range = document.createRange()
  range.selectNode(myElement)
  selection.addRange(range)
}**The most simplest answer works in all browsers**
  • Thank you for this code snippet, which might provide some limited, immediate help. A [proper explanation](https://meta.stackexchange.com/q/114762/349538) would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you’ve made. – jasie Apr 26 '21 at 13:17
  • Please consider explaining your answer so that everyone can understand it better. – Ajith Gopi Apr 26 '21 at 13:29