Retrieving DOM textnode position

Not directly. TextNode does not have the originally-IE offset* (and similar) extensions for measuring on-viewport positioning.

On IE only, you could create a TextRange object, laboriously attempt to align it with the bounds of the TextNode, then measure the boundingLeft/boundingTop of the TextRange, and add it to the position of the parent element (obtained by the usual means). However this is a bunch of work for a potentially-wobbly single-browser solution.

Another approach you might be able to get away with would be wrapping the text in a span element (either in the document, or dynamically and/or temporarily by script), and using the span to measure positioning, assuming it's not picking up any additional styles that may affect the position. Note however that a wrapped span may not give the expected right/bottom values; depending on what you want to do with it, you might end up wrapping the first and last character or some other arrangement.

In summary: urgh, nothing good.


Today you can via Range.getBoundingClientRect(). IE9+

// Get your text node
const el = document.querySelector('strong')
const textNode = el.firstChild;

// Get coordinates via Range
const range = document.createRange();
range.selectNode(textNode);
const coordinates = range.getBoundingClientRect()

console.log(coordinates);
/* Demo CSS, ignore, highlights box coordinates */ body{max-width:300px}strong{position:relative}strong,strong:before{border:solid 1px red}strong:before{content:'';position:absolute;right:100%;bottom:100%;width:100vw;height:100vh;pointer-events:none}
The red lines will show you the coordinates bounding box of the <strong>selected textnode</strong>.

Text node relative to viewport

function getBoundingClientRectText(textNode) {
  const range = document.createRange()
  range.selectNode(textNode)
  return range.getBoundingClientRect()
}

Text node relative to an element

function getTextOffsetRelativeToElement(element, textNode) {
  const elementRect = element.getBoundingClientRect()
  const range = document.createRange()
  range.selectNode(textNode)
  const textRect = range.getBoundingClientRect()
  return {
    top: textRect.top - elementRect.top,
    left: textRect.left - elementRect.left
  }
}

Character offset relative to text node's parent element

function getCharOffset(textNode, offset) {
  const parentRect = textNode.parentElement.getBoundingClientRect()
  const range = document.createRange()
  range.setStart(textNode, offset)
  range.setEnd(textNode, offset + 1)
  const charRect = range.getBoundingClientRect()
  return {
    top: charRect.top - parentRect.top,
    left: charRect.left - parentRect.left
  }
}

Tags:

Dom

Textnode