Get the Highlighted/Selected text
Asked Answered
A

7

450

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

Argolis answered 21/3, 2011 at 14:33 Comment(3)
Simple javascript worked for me. document.getSelection().anchorNode.data.substr(document.getSelection().anchorOffset, document.getSelection().focusOffset-document.getSelection().anchorOffset)Elecampane
@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.Consciencestricken
@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.Ostracism
C
601

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>
Consciencestricken answered 21/3, 2011 at 14:57 Comment(28)
What is the else if {} -fork good for? what is "Control" about?Argolis
@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 ControlRanges have no text property.Consciencestricken
Can this function be called after any event? It doesn't seem to work for me on a textareaSmart
@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.Ranie
@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() 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 of my own Rangy library.Consciencestricken
@Tim Down, thanks for a quick anwser. Another question, how to highlight the mouse selection part? I think use regexp is worse.Ranie
@cj333: The simplest way is using document.execCommand(): #2583331Consciencestricken
Fantastic - can even modify window and document to an iframe's contentWindow and contentDocument, respectively, and it still works just fine.Municipality
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.Inoculation
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"Constituency
@Auspex: Not in this case: jQuery has no handling for selections at all, and nor should it.Consciencestricken
@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 (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.Constituency
@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.Consciencestricken
I already know that you are aware of the following, @TimDown, but it should be noted, that this won't work on textareas in Firefox. This is a known bug.Novelette
..look at this answer to get it working in that case. :) Here is a working fiddle with the function I use: 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..Novelette
@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.Consciencestricken
@Dennis98: ... can't find it though. I'll add it here since this seems to be a popular version of this question.Consciencestricken
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.. :PNovelette
@Dennis98: Fair enough. Just out of interest, which bit do you think is overdoing it?Consciencestricken
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: jsfiddle.net/6zoposby vs. jsfiddle.net/6zoposby/1Novelette
@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.oNovelette
@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 <input> element type (such as "number") that doesn't support it (see 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.Consciencestricken
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.. ;)Novelette
Hey guys. I wanted to know if I can add text at the beginning and the end of the selection. ThanksBertiebertila
@beraki: I've definitely posted code for that somewhere on SO before. You can do it in inputs and textareas with my jQuery plugin (github.com/timdown/rangyinputs) and in regular content (including contenteditable) you can use #17498161.Consciencestricken
why are you using input fields? is it not possible to get the content of a div?Geographical
@Anthony: My original answer was just for getting the selection within regular content such as divs. 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.Consciencestricken
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:""}Constantan
O
144

Get highlighted text this way:

window.getSelection().toString()

and of course a special treatment for ie:

document.selection.createRange().htmlText
Orvas answered 19/6, 2014 at 14:47 Comment(3)
For IE>=10 “document.selection support was removed in IE10 and replaced with window.getSelection”. Source: connect.microsoft.com/IE/feedback/details/795325/…Blackpoll
This will fail under multiple conditions in various browsers (e.g. Firefox).Misapprehension
August 2020: It is worth noting that currently getSelection() doesn't work on the content of <textarea> and <input> elements in Firefox, Edge (Legacy) and Internet Explorer. HTMLInputElement.setSelectionRange() or the selectionStart and selectionEnd properties could be used to work around this.Mischance
J
21

Use window.getSelection().toString().

You can read more on developer.mozilla.org

Jolda answered 5/6, 2020 at 8:16 Comment(1)
While true, how is this different from the older answers? (Comments on the other answers about this not always working, also apply here.)Mischance
V
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)
Verticillaster answered 20/3, 2012 at 20:2 Comment(0)
B
13

Yes you can do it with simple JavaScript snippet:

document.addEventListener('mouseup', event => {  
    if(window.getSelection().toString().length){
       let exactText = window.getSelection().toString();        
    }
}
Blackett answered 28/8, 2020 at 6:35 Comment(0)
D
10

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());
    });
Dorolisa answered 24/7, 2021 at 14:3 Comment(0)
P
0

Just find another way to do it. window.getSelection() is just frustratingly poorly designed. It should have been a text based function, not a node based function from day 1.

Let's take something really basic - you want to highlight a text an make that section bold. Great, window.getSelection() is fantastic for that...once.

However since you also want to make part of that text italic...well...now you're screwed. The text you want to highlight is now divided between 2 or potentially more nodes...which is an issue when the starting point given by window.getSelection() only applies to the specified node and does not take formating into account - the amount of characters to the right of the node that the beginging of the text is in when it's ivided up into several nodes...it just beecomes a fantastic mess.

You can no longer look up the selected phrase in it's entirety as tags like or
will result in you not finding the text, or, if you look up without formatting then you now need to loop through each and every character - and even then you may have several pieces of text that are the same, so looping through the nodes won't help you get where you should do your edits to the text anyways, since you now need to crossrefference formatted and unformatted text...

just don't use it, it's garbage from an era where bad programmers saw it as their duty to dictate what browser you use or how you should highlight text - and if something was buggy or wrong it's the users fault for not doing things the way the programmer wanted them to.

Code something better yourself from scratch instad.

Hell, even something like putting all the letters in an array where each item in the array is a seperate letter and then decide starting point and ending point with onmousedown/onmouseup is simpler an faster instead if you having to deal with window.getSelection() utter garbage is what it is.

It is woefully unfit for 99% of eeverything you want it to do.

It would have been so much better with `getSelected(text); returning the position of the first and last character as well as the selected text. Or divide it up in 3 seperate functions for all I care.

That woul have been a thousand times better.

Pivotal answered 26/2 at 14:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.