[javascript] How to get element by innerText

How to get tag in html page, if I know what text tag contains. E.g.:

<a ...>SearchingText</a>

This question is related to javascript jquery innertext

The answer is


Simply pass your substring into the following line:

Outer HTML

document.documentElement.outerHTML.includes('substring')

Inner HTML

document.documentElement.innerHTML.includes('substring')

You can use these to search through the entire document and retrieve the tags that contain your search term:

function get_elements_by_inner(word) {
    res = []
    elems = [...document.getElementsByTagName('a')];
    elems.forEach((elem) => { 
        if(elem.outerHTML.includes(word)) {
            res.push(elem)
        }
    })
    return(res)
}

Usage:

How many times is the user "T3rm1" mentioned on this page?

get_elements_by_inner("T3rm1").length

1

How many times is jQuery mentioned?

get_elements_by_inner("jQuery").length

3

Get all elements containing the word "Cybernetic":

get_elements_by_inner("Cybernetic")

enter image description here


I found the use of the newer syntax a little bit shorter compared to the others answer. So here's my proposal:

const callback = element => element.innerHTML == 'My research'

const elements = Array.from(document.getElementsByTagName('a'))
// [a, a, a, ...]

const result = elements.filter(callback)

console.log(result)
// [a]

JSfiddle.net


While it's possible to get by the inner text, I think you are heading the wrong way. Is that inner string dynamically generated? If so, you can give the tag a class or -- better yet -- ID when the text goes in there. If it's static, then it's even easier.


You can use jQuery :contains() Selector

var element = $( "a:contains('SearchingText')" );

You can use a TreeWalker to go over the DOM nodes, and locate all text nodes that contain the text, and return their parents:

_x000D_
_x000D_
const findNodeByContent = (text, root = document.body) => {_x000D_
  const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);_x000D_
_x000D_
  const nodeList = [];_x000D_
_x000D_
  while (treeWalker.nextNode()) {_x000D_
    const node = treeWalker.currentNode;_x000D_
_x000D_
    if (node.nodeType === Node.TEXT_NODE && node.textContent.includes(text)) {_x000D_
      nodeList.push(node.parentNode);_x000D_
    }_x000D_
  };_x000D_
_x000D_
  return nodeList;_x000D_
}_x000D_
_x000D_
const result = findNodeByContent('SearchingText');_x000D_
_x000D_
console.log(result);
_x000D_
<a ...>SearchingText</a>
_x000D_
_x000D_
_x000D_


This does the job.
Returns an array of nodes containing text.

function get_nodes_containing_text(selector, text) {
    const elements = [...document.querySelectorAll(selector)];

    return elements.filter(
      (element) =>
        element.childNodes[0]
        && element.childNodes[0].nodeValue
        && RegExp(text, "u").test(element.childNodes[0].nodeValue.trim())
    );
  }

Functional approach. Returns array of all matched elements and trims spaces around while checking.

function getElementsByText(str, tag = 'a') {
  return Array.prototype.slice.call(document.getElementsByTagName(tag)).filter(el => el.textContent.trim() === str.trim());
}

Usage

getElementsByText('Text here'); // second parameter is optional tag (default "a")

if you're looking through different tags i.e. span or button

getElementsByText('Text here', 'span');
getElementsByText('Text here', 'button');

The default value tag = 'a' will need Babel for old browsers


To get the filter method from user1106925 working in <=IE11 if needed

You can replace the spread operator with:

[].slice.call(document.querySelectorAll("a"))

and the includes call with a.textContent.match("your search term")

which works pretty neatly:

[].slice.call(document.querySelectorAll("a"))
   .filter(a => a.textContent.match("your search term"))
   .forEach(a => console.log(a.textContent))

I think you'll need to be a bit more specific for us to help you.

  1. How are you finding this? Javascript? PHP? Perl?
  2. Can you apply an ID attribute to the tag?

If the text is unique (or really, if it's not, but you'd have to run through an array) you could run a regular expression to find it. Using PHP's preg_match() would work for that.

If you're using Javascript and can insert an ID attribute, then you can use getElementById('id'). You can then access the returned element's attributes through the DOM: https://developer.mozilla.org/en/DOM/element.1.


I've just needed a way to get the element that contains a specific text and this is what I came up with.

Use document.getElementsByInnerText() to get multiple elements (multiple elements might have the same exact text), and use document.getElementByInnerText() to get just one element (first match).

Also, you can localize the search by using an element (e.g. someElement.getElementByInnerText()) instead of document.

You might need to tweak it in order to make it cross-browser or satisfy your needs.

I think the code is self-explanatory, so I'll leave it as it is.

_x000D_
_x000D_
HTMLElement.prototype.getElementsByInnerText = function (text, escape) {_x000D_
    var nodes  = this.querySelectorAll("*");_x000D_
    var matches = [];_x000D_
    for (var i = 0; i < nodes.length; i++) {_x000D_
        if (nodes[i].innerText == text) {_x000D_
            matches.push(nodes[i]);_x000D_
        }_x000D_
    }_x000D_
    if (escape) {_x000D_
        return matches;_x000D_
    }_x000D_
    var result = [];_x000D_
    for (var i = 0; i < matches.length; i++) {_x000D_
        var filter = matches[i].getElementsByInnerText(text, true);_x000D_
        if (filter.length == 0) {_x000D_
            result.push(matches[i]);_x000D_
        }_x000D_
    }_x000D_
    return result;_x000D_
};_x000D_
document.getElementsByInnerText = HTMLElement.prototype.getElementsByInnerText;_x000D_
_x000D_
HTMLElement.prototype.getElementByInnerText = function (text) {_x000D_
    var result = this.getElementsByInnerText(text);_x000D_
    if (result.length == 0) return null;_x000D_
    return result[0];_x000D_
}_x000D_
document.getElementByInnerText = HTMLElement.prototype.getElementByInnerText;_x000D_
_x000D_
console.log(document.getElementsByInnerText("Text1"));_x000D_
console.log(document.getElementsByInnerText("Text2"));_x000D_
console.log(document.getElementsByInnerText("Text4"));_x000D_
console.log(document.getElementsByInnerText("Text6"));_x000D_
_x000D_
console.log(document.getElementByInnerText("Text1"));_x000D_
console.log(document.getElementByInnerText("Text2"));_x000D_
console.log(document.getElementByInnerText("Text4"));_x000D_
console.log(document.getElementByInnerText("Text6"));
_x000D_
<table>_x000D_
    <tr>_x000D_
        <td>Text1</td>_x000D_
    </tr>_x000D_
    <tr>_x000D_
        <td>Text2</td>_x000D_
    </tr>_x000D_
    <tr>_x000D_
        <td>_x000D_
            <a href="#">Text2</a>_x000D_
        </td>_x000D_
    </tr>_x000D_
    <tr>_x000D_
        <td>_x000D_
            <a href="#"><span>Text3</span></a>_x000D_
        </td>_x000D_
    </tr>_x000D_
    <tr>_x000D_
        <td>_x000D_
            <a href="#">Special <span>Text4</span></a>_x000D_
        </td>_x000D_
    </tr>_x000D_
    <tr>_x000D_
        <td>_x000D_
            Text5_x000D_
            <a href="#">Text6</a>_x000D_
            Text7_x000D_
        </td>_x000D_
    </tr>_x000D_
</table>
_x000D_
_x000D_
_x000D_


_x000D_
_x000D_
function findByTextContent(needle, haystack, precise) {_x000D_
  // needle: String, the string to be found within the elements._x000D_
  // haystack: String, a selector to be passed to document.querySelectorAll(),_x000D_
  //           NodeList, Array - to be iterated over within the function:_x000D_
  // precise: Boolean, true - searches for that precise string, surrounded by_x000D_
  //                          word-breaks,_x000D_
  //                   false - searches for the string occurring anywhere_x000D_
  var elems;_x000D_
_x000D_
  // no haystack we quit here, to avoid having to search_x000D_
  // the entire document:_x000D_
  if (!haystack) {_x000D_
    return false;_x000D_
  }_x000D_
  // if haystack is a string, we pass it to document.querySelectorAll(),_x000D_
  // and turn the results into an Array:_x000D_
  else if ('string' == typeof haystack) {_x000D_
    elems = [].slice.call(document.querySelectorAll(haystack), 0);_x000D_
  }_x000D_
  // if haystack has a length property, we convert it to an Array_x000D_
  // (if it's already an array, this is pointless, but not harmful):_x000D_
  else if (haystack.length) {_x000D_
    elems = [].slice.call(haystack, 0);_x000D_
  }_x000D_
_x000D_
  // work out whether we're looking at innerText (IE), or textContent _x000D_
  // (in most other browsers)_x000D_
  var textProp = 'textContent' in document ? 'textContent' : 'innerText',_x000D_
    // creating a regex depending on whether we want a precise match, or not:_x000D_
    reg = precise === true ? new RegExp('\\b' + needle + '\\b') : new RegExp(needle),_x000D_
    // iterating over the elems array:_x000D_
    found = elems.filter(function(el) {_x000D_
      // returning the elements in which the text is, or includes,_x000D_
      // the needle to be found:_x000D_
      return reg.test(el[textProp]);_x000D_
    });_x000D_
  return found.length ? found : false;;_x000D_
}_x000D_
_x000D_
_x000D_
findByTextContent('link', document.querySelectorAll('li'), false).forEach(function(elem) {_x000D_
  elem.style.fontSize = '2em';_x000D_
});_x000D_
_x000D_
findByTextContent('link3', 'a').forEach(function(elem) {_x000D_
  elem.style.color = '#f90';_x000D_
});
_x000D_
<ul>_x000D_
  <li><a href="#">link1</a>_x000D_
  </li>_x000D_
  <li><a href="#">link2</a>_x000D_
  </li>_x000D_
  <li><a href="#">link3</a>_x000D_
  </li>_x000D_
  <li><a href="#">link4</a>_x000D_
  </li>_x000D_
  <li><a href="#">link5</a>_x000D_
  </li>_x000D_
</ul>
_x000D_
_x000D_
_x000D_

Of course, a somewhat simpler way still is:

_x000D_
_x000D_
var textProp = 'textContent' in document ? 'textContent' : 'innerText';_x000D_
_x000D_
// directly converting the found 'a' elements into an Array,_x000D_
// then iterating over that array with Array.prototype.forEach():_x000D_
[].slice.call(document.querySelectorAll('a'), 0).forEach(function(aEl) {_x000D_
  // if the text of the aEl Node contains the text 'link1':_x000D_
  if (aEl[textProp].indexOf('link1') > -1) {_x000D_
    // we update its style:_x000D_
    aEl.style.fontSize = '2em';_x000D_
    aEl.style.color = '#f90';_x000D_
  }_x000D_
});
_x000D_
<ul>_x000D_
  <li><a href="#">link1</a>_x000D_
  </li>_x000D_
  <li><a href="#">link2</a>_x000D_
  </li>_x000D_
  <li><a href="#">link3</a>_x000D_
  </li>_x000D_
  <li><a href="#">link4</a>_x000D_
  </li>_x000D_
  <li><a href="#">link5</a>_x000D_
  </li>_x000D_
</ul>
_x000D_
_x000D_
_x000D_

References:


Using the most modern syntax available at the moment, it can be done very cleanly like this:

for (const a of document.querySelectorAll("a")) {
  if (a.textContent.includes("your search term")) {
    console.log(a.textContent)
  }
}

Or with a separate filter:

[...document.querySelectorAll("a")]
   .filter(a => a.textContent.includes("your search term"))
   .forEach(a => console.log(a.textContent))

Naturally, legacy browsers won't handle this, but you can use a transpiler if legacy support is needed.


You could use xpath to accomplish this

var xpath = "//a[text()='SearchingText']";
var matchingElement = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

You can also search of an element containing some text using this xpath:

var xpath = "//a[contains(text(),'Searching')]";