I have a code
element, and I know the text I'm looking for is inside it, for example:
<p>
Lorem ipsum <span class="bold">dolor</span> sit amet
</p>
Note the span
that is used for styling specific words.
Now, assume I have a reference to the p
element, and I want to programmatically mark the ipsum dolor sit
part, how can achieve that?
You can use the Selection
API with a Range
argument to programmatically select text in an element.
The Range
start and end positions accept a Child Node number, or Character inside a Text
node. In our case, we need to reach the Text
nodes to direct to the text position inside them (in our example, it will start on the first Text
node of p
, in position 11
, and will end on the last Text
in position 4
).
To find the right node and the text position inside it, use the next function:
const findPositionInsideTree = (node, position) => {
if (node.nodeType === Node.TEXT_NODE) {
return { node, position };
}
for (let child of node.childNodes) {
if (position <= child.textContent.length) return findPositionInsideTree(child, position);
position -= child.textContent.length;
}
};
This recursive code loops over the child nodes and counts the expected position inside each node.
And now you only need to call this function for your text, create a Range
and add it to the Selection
:
const textStart = element.textContent.indexOf('ipsum dolor sit');
const textEnd = textStart + 'ipsum dolor sit'.length;
const start = findPositionInsideTree(element, textStart);
const end = findPositionInsideTree(element, textEnd);
const range = new Range();
range.setStart(start.node, start.position);
range.setEnd(end.node, end.position);
window.getSelection().removeAllRanges()
window.getSelection().addRange(range)