Search code examples
javascriptdomtreewalker

How to use scrollIntoView from text node


I can't figure out how to get the element of a text node but I can get the parent element.

I've written a javascript routine to make a selection using a range. So I have a start node and end node which have been obtained with document.createTreeWalker(rootnode, NodeFilter.SHOW_TEXT, null, false).

I want to use scrollIntoView() but it seems I can only call this from an element. So at the moment I'm using startNode.parentElement.scrollIntoView.

let range = new Range()
range.setStart(startNode, startPos)
range.setEnd(endNode, endPos)
document.getSelection().removeAllRanges()
document.getSelection().addRange(range)
startNode.parentElement.scrollIntoView({ behavior: 'instant', block: 'start', inline: 'start' })

All good when the tags are small but if it were a large paragraph of text then the parent position could be a fair way off the actual elements position. Is there a way to get the element of a text node so I can call scrollIntoView?

As a work around I'm using range.getBoundingClientRect() and then setting the scrollTop of the page.

let bb=range.getBoundingClientRect()
pagetop.parentElement.scrollTop = bb.y+pagetop.parentElement.scrollTop-130 // 130 fudge value

It works :), but I'd rather use scrollIntoView or at least have a better understanding of what I'm doing wrong.


Solution

  • To scroll to a text node in JavaScript, you can't use scrollIntoView() directly on the text node. But, you can use a workaround by creating a temporary element.
    Like creating a <span> element right where you want, and scroll to that and then remove it from the DOM.

    let range = new Range();
    range.setStart(startNode, startPos);
    range.setEnd(endNode, endPos);
    
    let tempSpan = document.createElement('span');
    range.insertNode(tempSpan);
    
    tempSpan.scrollIntoView({ behavior: 'instant', block: 'start' });
    tempSpan.remove();
    
    document.getSelection().addRange(range);