[jquery] Select element by exact match of its content

All right, I wonder if there is a way to make the :contains() jQuery's selector to select elements with only the string that is typed in

for example -

<p>hello</p>
<p>hello world</p>

$('p:contains("hello")').css('font-weight', 'bold');

The selector will select both p elements and make them bold, but I want it to select only the first one.

This question is related to jquery jquery-selectors

The answer is


No, there's no jQuery (or CSS) selector that does that.

You can readily use filter:

$("p").filter(function() {
    return $(this).text() === "hello";
}).css("font-weight", "bold");

It's not a selector, but it does the job. :-)

If you want to handle whitespace before or after the "hello", you might throw a $.trim in there:

return $.trim($(this).text()) === "hello";

For the premature optimizers out there, if you don't care that it doesn't match <p><span>hello</span></p> and similar, you can avoid the calls to $ and text by using innerHTML directly:

return this.innerHTML === "hello";

...but you'd have to have a lot of paragraphs for it to matter, so many that you'd probably have other issues first. :-)


You can use jQuery's filter() function to achieve this.

$("p").filter(function() {
// Matches exact string   
return $(this).text() === "Hello World";
}).css("font-weight", "bold");

Try add a extend pseudo function:

$.expr[':'].textEquals = $.expr.createPseudo(function(arg) {
    return function( elem ) {
        return $(elem).text().match("^" + arg + "$");
    };
});

Then you can do:

$('p:textEquals("Hello World")');

An one-liner that works with alternative libraries to jQuery:

$('p').filter((i, p) => $(p).text().trim() === "hello").css('font-weight', 'bold');

And this is the equivalent to a jQuery's a:contains("pattern") selector:

var res = $('a').filter((i, a) => $(a).text().match(/pattern/));

The .first() will help here

$('p:contains("hello")').first().css('font-weight', 'bold');

Like T.J. Crowder stated above, the filter function does wonders. It wasn't working for me in my specific case. I needed to search multiple tables and their respective td tags inside a div (in this case a jQuery dialog).

$("#MyJqueryDialog table tr td").filter(function () {
    // The following implies that there is some text inside the td tag.
    if ($.trim($(this).text()) == "Hello World!") {
       // Perform specific task.
    }
});

I hope this is helpful to someone!


I found a way that works for me. It is not 100% exact but it eliminates all strings that contain more than just the word I am looking for because I check for the string not containing individual spaces too. By the way you don't need these " ". jQuery knows you are looking for a string. Make sure you only have one space in the :contains( ) part otherwise it won't work.

<p>hello</p>
<p>hello world</p>
$('p:contains(hello):not(:contains( ))').css('font-weight', 'bold');

And yes I know it won't work if you have stuff like <p>helloworld</p>


So Amandu's answer mostly works. Using it in the wild, however, I ran into some issues, where things that I would have expected to get found were not getting found. This was because sometimes there is random white space surrounding the element's text. It is my belief that if you're searching for "Hello World", you would still want it to match " Hello World ", or even "Hello World \n". Thus, I just added the "trim()" method to the function, which removes surrounding whitespace, and it started to work better.

Specifically...

$.expr[':'].textEquals = function(el, i, m) {
    var searchText = m[3];
    var match = $(el).text().trim().match("^" + searchText + "$")
    return match && match.length > 0;
}

Also, note, this answer is extremely similar to Select link by text (exact match)

And secondary note... trim only removes whitespace before and after the searched text. It does not remove whitespace in the middle of the words. I believe this is desirable behavior, but you could change that if you wanted.