How can I find elements by text content with jQuery?

JqueryTextFind

Jquery Problem Overview


Can anyone tell me if it's possible to find an element based on its content rather than by an ID or class?

I am attempting to find elements that don't have distinct classes or IDs. (Then I then need to find that element's parent.)

Jquery Solutions


Solution 1 - Jquery

You can use the :contains selector to get elements based on their content.

Demo here

$('div:contains("test")').css('background-color', 'red');

<div>This is a test</div>
<div>Another Div</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

Solution 2 - Jquery

In jQuery documentation it says:

> The matching text can appear directly within the selected element, in > any of that element's descendants, or a combination

Therefore it is not enough that you use :contains() selector, you also need to check if the text you search for is the direct content of the element you are targeting for, something like that:

function findElementByText(text) {
    var jSpot = $("b:contains(" + text + ")")
                .filter(function() { return $(this).children().length === 0;})
	            .parent();  // because you asked the parent of that element

    return jSpot;
}

Solution 3 - Jquery

Fellas, I know this is old but hey I've this solution which I think works better than all. First and foremost overcomes the Case Sensitivity that the jquery :contains() is shipped with:

var text = "text";

var search = $( "ul li label" ).filter( function ()
{
    return $( this ).text().toLowerCase().indexOf( text.toLowerCase() ) >= 0;
}).first(); // Returns the first element that matches the text. You can return the last one with .last()

Hope someone in the near future finds it helpful.

Solution 4 - Jquery

Rocket's answer doesn't work.

<div>hhhhhh
<div>This is a test</div>
<div>Another Div</div>
</div>

I simply modified his DEMO here and you can see the root DOM is selected.

$('div:contains("test"):last').css('background-color', 'red');

add ":last" selector in the code to fix this.

Solution 5 - Jquery

The following jQuery selects div nodes that contain text but have no children, which are the leaf nodes of the DOM tree.

$('div:contains("test"):not(:has(*))').css('background-color', 'red');

<div>div1
<div>This is a test, nested in div1</div>
<div>Nested in div1<div>
</div>
<div>div2 test
<div>This is another test, nested in div2</div>
<div>Nested in div2</div>
</div>
<div>
div3
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

Solution 6 - Jquery

Best way in my opinion.

$.fn.findByContentText = function (text) {
    return $(this).contents().filter(function () {
        return $(this).text().trim() == text.trim();
    });
};

Solution 7 - Jquery

Yes, use the jQuery contains selector.

Solution 8 - Jquery

All answers so far do not match all specific elements containing a direct child text node which contains a specific text.

Consider the following example. We want to find all hobbits, that is, all divs containing a direct child text node, which contains the word "hobbit" (including word borders, ignoring the case).

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Find the hobbits</title>
    </head>
    <body>
        <div name='Tolkien'>
            book writer
            <div name='Elrond'>
                elven king
                <div name='Arwen'>elven princess</div>
                <div name='Aragorn'>human king, son-in-law</div>
            </div>
            <div name='Gandalf'>
                wizard, expert for hobbits
                <div name='Bilbo'>
                    old hobbit
                    <div name='Frodo'>
                        young hobbit
                        <div name='Samweis'>best friend hobbit</div>
                    </div>
                </div>
                <div name='Gollum'>ex hobbit</div>
                <div name='Odo'>hobbit</div>
            </div>
        </div>
        <script src= "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    </body>
</html>

div {
    margin:10px 0;
    padding: 10px;
    border: 1px solid silver;
    color: silver;
    font-style:italic;
}

div:before {
    display:block;
    content: attr(name);
    font-style:normal;
}

/* Inserted by SO, we are not interested in it */
body + div {
    display: none;
}

$(function() {
    
    const ELEMTYPE = Node.ELEMENT_NODE
    const TEXTTYPE = Node.TEXT_NODE
    
    /*
    Behaves a bit like Python's os.walk().
    The `topdown` parameter is not strictly necessary for this example.
    */
    function* walk_text(root, topdown=true) {
        const childs = []
        const textchilds = []
        for (const child of root.childNodes) {
            const childtype = child.nodeType
            if (childtype === ELEMTYPE) {
                childs.push(child)
            } else if (childtype === TEXTTYPE) {
                textchilds.push(child)
            }
        }
        if (topdown) {
            yield [root, textchilds]
        }
        for (const child of childs) {
            yield* walk_text(child, topdown)
        }
        if (!topdown) {
            yield [root, textchilds]
        }
    }
    
    function* walk_matching(startnode, nodepat, textpat) {
        for ( [elem, textchilds] of walk_text(startnode) ) {
            if ( nodepat.test(elem.nodeName) ) {
                for ( const textchild of textchilds ) {
                    if ( textpat.test(textchild.nodeValue) ) {
                        yield elem
                        break
                    }
                }
            }
        }
    }
    
    // raw dom node
    let startnode = $('body')[0]
    
    // search for element nodes with names matching this pattern ...
    let nodepat = /^div$/i
    
    // ... containing direct child text nodes matching this pattern
    let textpat = /\bhobbit\b/i
    
    for ( const node of walk_matching( startnode, nodepat, textpat ) ) {
        $(node).css({
            border: '1px solid black',
            color: 'black'
        })
    }

});

The other answers find (when searching for 'hobbit'):

  • Rocket Hazmat's answer: Tolkien, Gandalf, Bilbo, Frodo, Samweis, Gollum, Odo
  • Morgs's answer: Tolkien
  • yoav barnea's answer: Gandalf, Frodo
  • Nicholas Sushkin's answer: Samweis, Gollum, Odo
  • Rocket Hazmat's answer in the comments, Terry Lin's answer, rplaurindo's answer: Odo

All of these answers make sense, depending on what you want to do. Choose wise, because Rocket Hazmat's answers, Morgs's answer and Terry Lin's answer partially perform more than two times faster than my solution. I guess that is because they don't need to walk through the whole DOM. Most answers who use .filter() perform very fast.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsiskoView Question on Stackoverflow
Solution 1 - Jquerygen_EricView Answer on Stackoverflow
Solution 2 - Jqueryyoav barneaView Answer on Stackoverflow
Solution 3 - JqueryMorgsView Answer on Stackoverflow
Solution 4 - JqueryTerry LinView Answer on Stackoverflow
Solution 5 - JqueryNicholas SushkinView Answer on Stackoverflow
Solution 6 - JqueryrplaurindoView Answer on Stackoverflow
Solution 7 - JqueryAlex TurpinView Answer on Stackoverflow
Solution 8 - JqueryNils LindemannView Answer on Stackoverflow