444

Is it possible to get the highlighted text in a paragraph of a website e.g. by using jQuery?

Damjan Pavlica
  • 31,277
  • 10
  • 71
  • 76
Dan
  • 4,481
  • 3
  • 15
  • 3
  • 1
    Simple javascript worked for me. document.getSelection().anchorNode.data.substr(document.getSelection().anchorOffset, document.getSelection().focusOffset-document.getSelection().anchorOffset) – Rohit Verma Jun 27 '17 at 10:15
  • 3
    @RohitVerma: That's only going to work in the simple case of a selection that is contained within a single text node, which is by no means guaranteed to be the case. – Tim Down Nov 09 '17 at 10:17
  • @Dipak How do you replicate the social-sharing functionality from the blog you reference in your post? Instead of just returning the selected string, I'm trying to populate that variable into a twitter link. –  Mar 26 '18 at 19:09

6 Answers6

592

Getting the text the user has selected is relatively simple. There's no benefit to be gained by involving jQuery since you need nothing other than the window and document objects.

function getSelectionText() {
    var text = "";
    if (window.getSelection) {
        text = window.getSelection().toString();
    } else if (document.selection && document.selection.type != "Control") {
        text = document.selection.createRange().text;
    }
    return text;
}

If you're interested in an implementation that will also deal with selections in <textarea> and texty <input> elements, you could use the following. Since it's now 2016 I'm omitting the code required for IE <= 8 support but I've posted stuff for that in many places on SO.

function getSelectionText() {
    var text = "";
    var activeEl = document.activeElement;
    var activeElTagName = activeEl ? activeEl.tagName.toLowerCase() : null;
    if (
      (activeElTagName == "textarea") || (activeElTagName == "input" &&
      /^(?:text|search|password|tel|url)$/i.test(activeEl.type)) &&
      (typeof activeEl.selectionStart == "number")
    ) {
        text = activeEl.value.slice(activeEl.selectionStart, activeEl.selectionEnd);
    } else if (window.getSelection) {
        text = window.getSelection().toString();
    }
    return text;
}

document.onmouseup = document.onkeyup = document.onselectionchange = function() {
  document.getElementById("sel").value = getSelectionText();
};
Selection:
<br>
<textarea id="sel" rows="3" cols="50"></textarea>
<p>Please select some text.</p>
<input value="Some text in a text input">
<br>
<input type="search" value="Some text in a search input">
<br>
<input type="tel" value="4872349749823">
<br>
<textarea>Some text in a textarea</textarea>
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • 9
    What is the else if {} -fork good for? what is "Control" about? – Dan Mar 27 '11 at 10:30
  • 31
    @Dan: Sorry, I missed this question (don't think SO alerted me to it). The second branch is for IE <= 8 (IE 9 implements `window.getSelection()`). The `document.selection.type` check is testing that the selection is a text selection rather than a control selection. In IE, a control selection is a selection inside an editable element containing one or more elements (such as images and form controls) with outlines and resize handles. If you call `.createRange()` on such a selection, you get a `ControlRange` rather than a `TextRange`, and `ControlRange`s have no `text` property. – Tim Down Mar 30 '11 at 15:30
  • Can this function be called after any event? It doesn't seem to work for me on a textarea – Rafael Jun 03 '14 at 12:28
  • @Tim Down, +1, Is this work in all the model browser? And how to do the select not break the words? ( if here has one sentence `today is a wonderful day` then user select `day is a wonderful d`, it world complete select the whole sentence automaticlly.) Thanks. – cj333 Aug 04 '14 at 18:45
  • @cj333: Yes, this will work in all major browsers, including old versions of IE (back to version 4, I think). As to expanding to whole words, some browsers have built-in features (`TextRange` in IE has an [`expand()`](http://msdn.microsoft.com/en-gb/library/ie/ms536421(v=vs.85).aspx) method) and WebKit has a non-standard `expand()` method in its DOM Range extension. However, this doesn't cover all browsers. One (somewhat heavyweight) option for a cross-browser solution is the [TextRange module](https://github.com/timdown/rangy/wiki/Text-Range-Module) of my own Rangy library. – Tim Down Aug 04 '14 at 22:43
  • @Tim Down, thanks for a quick anwser. Another question, how to highlight the mouse selection part? I think use regexp is worse. – cj333 Aug 05 '14 at 07:39
  • @cj333: The simplest way is using `document.execCommand()`: http://stackoverflow.com/questions/2582831/how-can-i-highlight-the-text-of-the-dom-range-object – Tim Down Aug 05 '14 at 09:19
  • Fantastic - can even modify window and document to an iframe's contentWindow and contentDocument, respectively, and it still works just fine. – Two-Bit Alchemist Sep 15 '14 at 00:44
  • Just though I would add to this, if you want this to also include selected text in an `input` to be included, you can conditionally use a combination of `document.activeElement` and the DOM properties `selectionStart`, `selectionEnd` and `value` of that active element to get its selected text. This was useful for me when I needed to disable left/right swipe when ANY text in the page was selected. – Turnerj Sep 22 '14 at 01:51
  • I can't help thinking that any time you have to code three conditions to handle different browsers, there _is_ a _"benefit to be gained by involving jQuery"_ – Auspex Feb 11 '15 at 15:01
  • @Auspex: Not in this case: jQuery has no handling for selections at all, and nor should it. – Tim Down Feb 11 '15 at 16:12
  • 2
    @TimDown It's very thin ice to ever say "jQuery doesn't have X", because of course, with the right plugin, it can do anything you can do in the browser with javascript. In this case, we have jquery.selection (http://madapaja.github.io/jquery.selection/). It's equally wrong to say "nor should it". I arrived here because I was looking for exactly this. I have a use case, and jQuery is the right solution. – Auspex Feb 15 '15 at 19:33
  • 9
    @Auspex: I kind of see your point but I disagree. A jQuery plugin is a library that has a dependency on jQuery; it is not itself jQuery. In the case of selection handling, jQuery itself provides precisely nothing (which is as it should be because selection handling is not what jQuery is for), so any solution that uses jQuery is using it incidentally. – Tim Down Feb 16 '15 at 00:58
  • 2
    I already know that you are aware of the following, @TimDown, but it should be noted, that this won't work on `textarea`s in Firefox. This is a [known bug](https://bugzilla.mozilla.org/show_bug.cgi?id=85686). – Dennis98 Sep 28 '16 at 15:13
  • ..look at [this answer](http://stackoverflow.com/a/13796228/3439786) to get it working in that case. :) Here is a working fiddle with the function I use: https://jsfiddle.net/r9xps0ws/ (I don't have the second check as in this answer because I don't care about IE 8 and lower and I'd say you shouldn't anymore, too, unless you *really* need to.. – Dennis98 Sep 28 '16 at 15:36
  • @Dennis98: I'm not sure adding the input/textarea branch is appropriate in the context of answering this particular question but I take your point. I think I've given in and added it in answers elsewhere on SO. – Tim Down Sep 28 '16 at 16:22
  • @Dennis98: ... can't find it though. I'll add it here since this seems to be a popular version of this question. – Tim Down Sep 28 '16 at 16:27
  • It was one of the first results for me and lacked this info, so I though it would be good to mention it. :) Especially because I was searching after that.. And yeah, I've also seen an answer from you where you point that out, hence the "I already know that you are aware of" - can't find it anymore though O.o, maybe from someone in a discussion with you. Didn't knew that that also applies to input elements btw - thanks! :) Though IMO you are overdoing it a bit with your current solution, but well, I'm not forced in using the exact same code as you.. :P – Dennis98 Sep 28 '16 at 20:22
  • @Dennis98: Fair enough. Just out of interest, which bit do you think is overdoing it? – Tim Down Sep 29 '16 at 10:49
  • Sry for the late answer, was busy. :D Well, your further checks seem unnecessary to me. Pretty much every browser supports `.activeElement` and I don't see the point for checking the type of the element as well as of `.selectionStart`, which is also supported by practically every browser. Maybe I forget thinking about some edge case, but at least in my extended test case of yours, your code offers no benefit compared to mine; they work exactly the same: https://jsfiddle.net/6zoposby/ vs. https://jsfiddle.net/6zoposby/1/ – Dennis98 Sep 30 '16 at 16:11
  • @TimDown PS: I don't want to appear like the _"I'm better than you in any way"_-type nor do I want to annoy you or whatever; sry if this was the case. :D I just want to know why you're doing it different, to learn or maybe even to point sth. out/make sth. clear you didn't think of.. ^^ EDIT: Why did you you choose `.splice()` instead of `.substring` btw? Is it faster? O.o – Dennis98 Sep 30 '16 at 16:11
  • 1
    @Dennis98: I'm not remotely annoyed or offended :) The check for the input types is because you get warnings in the console in Chrome if you try to access `selectionStart` or `selectionEnd` in an `` element type (such as "number") that doesn't support it (see https://jsfiddle.net/6zoposby/2/, for example). I left the check for the existence of `selectionStart` so that the code won't break in IE <= 8. I admit the check for `activeElement` is probably overkill now. I use `slice` because it's more powerful (though that's not useful here) and slightly shorter to type than `substring`. – Tim Down Sep 30 '16 at 16:24
  • Good to know! :) But I'd say you can remove the check for `selectionStart`, we already agreed on removing the 2nd branch from your first code anyway, which was also for compatibility with IE below v9.. ;) – Dennis98 Sep 30 '16 at 19:51
  • Hey guys. I wanted to know if I can add text at the beginning and the end of the selection. Thanks – Beraki Nov 16 '16 at 19:39
  • 1
    @beraki: I've definitely posted code for that somewhere on SO before. You can do it in inputs and textareas with my jQuery plugin (https://github.com/timdown/rangyinputs) and in regular content (including contenteditable) you can use http://stackoverflow.com/questions/17497661/insert-text-before-and-after-selection-in-a-contenteditable. – Tim Down Nov 17 '16 at 12:53
  • why are you using `input` fields? is it not possible to get the content of a `div`? – oldboy Nov 09 '17 at 00:14
  • @Anthony: My original answer was just for getting the selection within regular content such as `div`s. Someone then requested a more general solution that covers cases when the selection is within an `input` or `textarea`, so I obliged. If you don't need that then you can just use the first version of the function. – Tim Down Nov 09 '17 at 10:22
  • Here's the 1st function above, but compressed into a ***"one-liner"*** : `function getSelectionText(){var W=window,Ds=document.selection; return W.getSelection? W.getSelection().toString(): Ds&&Ds.type!="Control"? Ds.createRange().text:""}` – ashleedawg Dec 28 '22 at 01:05
143

Get highlighted text this way:

window.getSelection().toString()

and of course a special treatment for ie:

document.selection.createRange().htmlText
ParPar
  • 7,355
  • 7
  • 43
  • 56
  • 3
    For IE>=10 “`document.selection` _support was removed in IE10 and replaced with_ `window.getSelection`”. Source: https://connect.microsoft.com/IE/feedback/details/795325/window-getselection-and-document-selection-legacy-support – user2314737 May 19 '17 at 09:14
  • 2
    This will fail under multiple conditions in various browsers (e.g. Firefox). – Makyen Aug 12 '17 at 07:33
  • 4
    [August 2020](https://developer.mozilla.org/en-US/docs/Web/API/Window/getSelection): _It is worth noting that currently `getSelection()` doesn't work on the content of ` – Arjan Aug 02 '20 at 20:12
21

Use window.getSelection().toString().

You can read more on developer.mozilla.org

Ebuka
  • 616
  • 8
  • 13
  • 3
    While true, how is this different from the older answers? (Comments on the other answers about this not always working, also apply here.) – Arjan Aug 02 '20 at 20:10
14

This solution works if you're using chrome (can't verify other browsers) and if the text is located in the same DOM Element:

window.getSelection().anchorNode.textContent.substring(
  window.getSelection().extentOffset, 
  window.getSelection().anchorOffset)
oers
  • 18,436
  • 13
  • 66
  • 75
Andrew Kennedy
  • 141
  • 1
  • 2
13

Yes you can do it with simple JavaScript snippet:

document.addEventListener('mouseup', event => {  
    if(window.getSelection().toString().length){
       let exactText = window.getSelection().toString();        
    }
}
Shardul Birje
  • 341
  • 5
  • 14
Aryesh
  • 386
  • 2
  • 16
8

You can use an event if you want

    document.addEventListener('selectionchange', (e)=>{
        console.log("Archor node - ",window.getSelection().anchorNode);
        console.log("Focus Node - ",window.getSelection().toString());
    });
MD SHAYON
  • 7,001
  • 45
  • 38