Can you set and/or change the user’s text selection in JavaScript?
Asked Answered
F

2

32

In JavaScript, there are various methods for accessing the user’s text selection, and creating text selections (or ranges) — see http://www.quirksmode.org/dom/range_intro.html.

As per that page, you can programmatically create a range, and access the text within that. But doing this doesn’t change the user’s text selection, or make the user have some selected text if they don’t already.

Can you set and/or change the user’s text selection in JavaScript?

Flatten answered 15/11, 2010 at 10:23 Comment(2)
you mean you want certain text in the page to suddenly appear selected? Blue highlight and everything?Vengeance
@Shadow: yup, that’s it.Flatten
C
9

Update 2021

The Selection API does this. Rather than making a new Selection() (which seemed intuitive, but doesn't work), window.getSelection() always returns a Selection object - even if nothing is highlighted by the user! You can then use setBaseAndExtent() to make a particular node be highlighted - this will change whatever is selected by the user (even if nothing is selected) to match what you specify.

The example below highlights the question in this StackOverflow page

const selection = window.getSelection()
const headerElement = document.querySelector('#question-header a')
selection.setBaseAndExtent(headerElement,0,headerElement,1)
Conductor answered 26/1, 2021 at 10:13 Comment(7)
Browser support looks pretty good, although window.getSelection doesn't work if you still need to support IE 8.Flatten
Also it's 2021 bro.Flatten
@PaulD.Waite Speaking of 2021 - IE8?Conductor
I bet someone's still using it.Flatten
This is fine unless you need to support any version of IE, including 11. The only relevant thing that has changed since my answer in 2010 is wider browser support for setBaseAndExtent(), which started out as WebKit-only, but it was never implemented in IE. The more roundabout way in my answer of creating a range and selecting it works in IE >= 9.Jettiejettison
Sure but the amount of people that support IE11 in 2021 is obviously fairly small. This answer is short, uses a simpler technique, and has links to MDN for the actual spec.Conductor
window.getSelection might actually return null according to typescriptPru
J
41

Yes. In all browsers you can get one or more Ranges or a TextRange from the user's selection, and both Range and TextRange have methods for changing the contents of the range.

UPDATE

You can set the user's selection by creating a Range and adding it to the Selection object in most browsers and by creating a TextRange and calling its select() method in IE <= 8.

For example, to set the selection to encompass the contents of an element:

function selectElementContents(el) {
    if (window.getSelection && document.createRange) {
        var sel = window.getSelection();
        var range = document.createRange();
        range.selectNodeContents(el);
        sel.removeAllRanges();
        sel.addRange(range);
    } else if (document.selection && document.body.createTextRange) {
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(el);
        textRange.select();
    }
}

There are also several methods of the Selection object that can be used to change the user's selection in non-IE browsers. If you can be more specific about how you want to change the selection then it will be easier to help.

Jettiejettison answered 15/11, 2010 at 10:28 Comment(7)
Ah yes, sorry, I didn’t phrase the question very well — I’m actually looking to set the user’s text selection when they don’t have one already.Flatten
is it possible to select different ranges simultaneously. I want to be able to select multiple parts of text that are discontinuous.Overtax
@Techsin: Yes, but only in Firefox. Call addRange() for each range you want to select.Jettiejettison
@TimDown: It would be very helpful, if you could add also non-IE method here.Bibcock
Note that range.selectNodeContents(el); might result in an unexpected value for range.endOffset/selection.focusOffset if el is not a pure text element. E.g. passing a span will most likely result in endOffset=1 while passing the span's text child will result in the correct offset. See this SO answer for more information.Rationale
@Griddo: It's only unexpected if you're not aware that a range offset can be relative to an element rather than just being restricted to a text node. Also, it's not the case that you should restrict selection offsets to just text nodes (think of non-text-containing elements such as <br> and <hr>).Jettiejettison
@TimDown You're absolutely right. It was just meant as a side note for someone who might be facing the same problem and (regarding the text nodes) as an example to illustrate my confusion, but not at all as a general suggestion or rule of thumb. To me, it was very un-intuitive, that selectNodeContents on <span>Hello World!</span> will visually select "Hello World!" but have an endOffset of 1 instead of 12. Once you familiarize yourself with the concepts of nodes, selections and ranges, it totally makes sense.Rationale
C
9

Update 2021

The Selection API does this. Rather than making a new Selection() (which seemed intuitive, but doesn't work), window.getSelection() always returns a Selection object - even if nothing is highlighted by the user! You can then use setBaseAndExtent() to make a particular node be highlighted - this will change whatever is selected by the user (even if nothing is selected) to match what you specify.

The example below highlights the question in this StackOverflow page

const selection = window.getSelection()
const headerElement = document.querySelector('#question-header a')
selection.setBaseAndExtent(headerElement,0,headerElement,1)
Conductor answered 26/1, 2021 at 10:13 Comment(7)
Browser support looks pretty good, although window.getSelection doesn't work if you still need to support IE 8.Flatten
Also it's 2021 bro.Flatten
@PaulD.Waite Speaking of 2021 - IE8?Conductor
I bet someone's still using it.Flatten
This is fine unless you need to support any version of IE, including 11. The only relevant thing that has changed since my answer in 2010 is wider browser support for setBaseAndExtent(), which started out as WebKit-only, but it was never implemented in IE. The more roundabout way in my answer of creating a range and selecting it works in IE >= 9.Jettiejettison
Sure but the amount of people that support IE11 in 2021 is obviously fairly small. This answer is short, uses a simpler technique, and has links to MDN for the actual spec.Conductor
window.getSelection might actually return null according to typescriptPru

© 2022 - 2024 — McMap. All rights reserved.