43

You can select a part of a web page with the mouse.

I know that I can get the currently selected text but how can I get the DOM element which contains the start or end of the current selection?

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820

2 Answers2

61

The following will return the container element of the start or end boundary of the current selection, using the boolean isStart to specify whether you want the start or end boundary. It will work in most mainstream browsers. Add feature tests for more robustness.

function getSelectionBoundaryElement(isStart) {
    var range, sel, container;
    if (document.selection) {
        range = document.selection.createRange();
        range.collapse(isStart);
        return range.parentElement();
    } else {
        sel = window.getSelection();
        if (sel.getRangeAt) {
            if (sel.rangeCount > 0) {
                range = sel.getRangeAt(0);
            }
        } else {
            // Old WebKit
            range = document.createRange();
            range.setStart(sel.anchorNode, sel.anchorOffset);
            range.setEnd(sel.focusNode, sel.focusOffset);

            // Handle the case when the selection was selected backwards (from the end to the start in the document)
            if (range.collapsed !== sel.isCollapsed) {
                range.setStart(sel.focusNode, sel.focusOffset);
                range.setEnd(sel.anchorNode, sel.anchorOffset);
            }
       }

        if (range) {
           container = range[isStart ? "startContainer" : "endContainer"];

           // Check if the container is a text node and return its parent if so
           return container.nodeType === 3 ? container.parentNode : container;
        }   
    }
}
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • what if I want to get the parent of the whole selection? Is that possible? – Flezcano Jul 17 '17 at 15:13
  • 1
    I was looking at that code and trying it out, really good. But it is not capable of returning two elements if 2 were selected. – Sara Kat Sep 19 '19 at 21:22
37

In IE, use document.selection.createRange().parentElement() and in real browsers use window.getSelection().getRangeAt(0).startContainer.parentNode. Something like this:

function getSelectedNode()
{
    if (document.selection)
        return document.selection.createRange().parentElement();
    else
    {
        var selection = window.getSelection();
        if (selection.rangeCount > 0)
            return selection.getRangeAt(0).startContainer.parentNode;
    }
}
InvisibleBacon
  • 3,137
  • 26
  • 27
  • 7
    This will give inconsistent results between browsers and doesn't answer the original question. In IE you get the element that contains the whole selection, while in other browsers you will get the parent of the node that contains the start of the selection (which could be a text node or an element). – Tim Down Sep 01 '09 at 10:35
  • This solution doesn't work for all cases. If you try to select more than one tag, all the subsequent tags except the first one will be ignored. The more universal solution is here: https://stackoverflow.com/a/5222955/1844247 – Serg May 27 '18 at 14:44