jQuery :contains() Selector

Beginner
7 min read
Updated: Oct 2026
5 examples
Live preview

What Is :contains()?

:contains(text) (since jQuery 1.1.4) selects elements whose text content includes the given string. The text may sit on the element itself, in any descendant, or both. Matching is case-sensitive. Quotes around the text are optional.

Remember
$("div:contains('John')")   // text includes "John"
$("div:contains(John)")     // same — quotes optional
$(":contains('John')")      // avoid — scans every element

// Case-sensitive: "john" ≠ "John"
// Prefer a tag or parent: $("#list li:contains('apple')")
NeedUse
Find by visible text$("div:contains('John')")
Scoped list search$("#list li:contains('x')")
Attribute substring$("[attr*='val']")
Has a matching child$(":has(sel)")
Exclude matches$(":not(:contains('x'))")
Custom text test.filter(fn)

How to Use :contains()

Pick a tag or container first, then filter by the substring you need.

  1. Start with a tag or scoped selector: $("div:contains('…')") or $("#box p:contains('…')").
  2. Pass the search string — with or without quotes; casing must match.
  3. Remember parents match when a child holds the text (aggregated text content).
  4. Do not use bare $(":contains('…')") on large pages — it scans everything.
  5. For attributes (not text), use [attr*="value"] instead.
PieceRequired?Role
textYesCase-sensitive substring to find
Tag / contextRecommendedLimits which elements are tested
QuotesOptionalBare word or '…' / "…"
Return value—jQuery collection of matching elements

Pseudocode

Pseudocode
matches = []
needle = given text   // case-sensitive

for each element in search context:
    haystack = element.textContent   // includes all descendants
    if haystack contains needle:
        matches.add(element)

return matches

Cheat Sheet

Keep these facts handy when searching by text.

TopicDetail
Syntax$("div:contains('text')")
SincejQuery 1.1.4
Standard?No — jQuery / Sizzle extension
CaseCase-sensitive
DescendantsYes — nested text counts
QuotesOptional around the text
vs attributesUse [attr*="…"] for attributes
Empty setNo match → length 0

Live Preview

Run div:contains(…) against the official-style name list.

Sample divs

  • John Resig
  • George Martin
  • Malcom John Sinclair
  • J. Ohn

Case-sensitive — try John vs john. J. Ohn does not contain John.

Result
$("div:contains('John')").length
→ 2

matched → John Resig, Malcom John Sinclair

jQuery Examples

Short, copy-ready snippets. Open DevTools Console, or use Try It Yourself for a live editor.

Example 1 — Official div:contains('John')

Find every div whose text includes John.

jQuery
var labels = [];
$("div:contains('John')").each(function () {
  labels.push($.trim($(this).text()));
});

$("#out").text(
  "Matched: " + labels.length + "\n" +
  labels.join(", ")
);
Try It Yourself

How It Works

  1. Query. $("div:contains('John')") tests each div’s text.
  2. Substring. Any occurrence of John counts — not a whole-word match.
  3. Skip. George Martin and J. Ohn do not contain John.
  4. Result. Two divs match — same as the official demo.

Example 2 — Case-Sensitive Search

Official rule: casing must match exactly.

jQuery
$("#out").text(
  "contains('John'): " + $("div:contains('John')").length + "\n" +
  "contains('john'): " + $("div:contains('john')").length
);
Try It Yourself

How It Works

  1. Exact case. John matches the text in the DOM.
  2. Lowercase. john is a different string — zero matches.
  3. Rule. Always copy the casing from your content.
  4. Need ignore-case? Use .filter() with a lowercased compare.

Example 3 — Text Inside Descendants

Parents match when a nested element holds the search string.

jQuery
var n = $("#card:contains('Sale')").length;
var spanOnly = $("#card span:contains('Sale')").length;

$("#out").text(
  "#card matches: " + n + "\n" +
  "span matches: " + spanOnly
);
Try It Yourself

How It Works

  1. Nested text. Sale lives inside a span.
  2. Parent. #card:contains('Sale') still matches the card.
  3. Child. You can also target the span directly.
  4. Watch out. Broad parents can over-match nested content.

Example 4 — Scoped List Filter

Search only inside one list so other page text is ignored.

jQuery
var labels = [];
$("#fruits li:contains('ap')").each(function () {
  labels.push($.trim($(this).text()));
});

$("#out").text(labels.join(", ") || "(none)");
Try It Yourself

How It Works

  1. Scope. #fruits li limits the search to that list.
  2. Substring. ap matches apple and grape.
  3. Skip. banana has no ap.
  4. Habit. Always prefer a parent id/class on real pages.

Example 5 — Text vs Attribute Contains

:contains() searches text; [attr*="…"] searches attributes.

jQuery
$("#out").text(
  "Text :contains('docs'): " + $("a:contains('docs')").length + "\n" +
  "Attr [href*='docs']: " + $("a[href*='docs']").length
);
Try It Yourself

How It Works

  1. Text. :contains('docs') looks at link label text.
  2. Attribute. [href*='docs'] looks at the URL string.
  3. Different jobs. One link can match both, either, or neither.
  4. Pick. Use text search for labels; attribute search for URLs/data.

Edge Cases & Pitfalls

Check these before shipping text-based filters.

case

Case-sensitive by design

:contains("john") will not match John. There is no built-in ignore-case flag.

parents

Parents match nested text

A container matches when any descendant holds the string. Scope to the element type you really want (e.g. li, not ul).

perf

Bare $(":contains()") is slow

It tests every element. Prefer $("div:contains()") or a parent context.

css

Not valid in native CSS APIs

querySelectorAll does not support :contains(). Keep it inside jQuery $().

Browser Support

:contains() is a jQuery extension (since 1.1.4). It works wherever your jQuery / Sizzle build runs — not in native CSS selectors.

✓ jQuery extension · 1.1.4+

jQuery :contains()

Supported across jQuery 1.x, 2.x, and 3.x in every browser that runs your jQuery build. Prefer current jQuery 3.x for modern projects.

100% jQuery selector support
Google Chrome All versions · Desktop & Mobile
Full support
Mozilla Firefox All versions · Desktop & Mobile
Full support
Apple Safari All versions · macOS & iOS
Full support
Microsoft Edge All versions · Chromium & Legacy
Full support
Internet Explorer IE 6+ · Legacy environments
Full support
Opera All modern versions
Full support
:contains() Universal (via jQuery)

Bottom line: Available everywhere jQuery runs. Scope the selector, respect case sensitivity, and remember it is not standard CSS.

Performance Notes

ApproachCostBest for
$("#id li:contains('x')")CheapestLocal text filters
$("div:contains('x')")ModerateSmall/medium pages
$(":contains('x')")ExpensiveAvoid on large DOMs
$("a[href*='x']")CheapAttribute substring (not text)

:contains() walks text content. Narrow the candidate set with a tag or parent before applying the text filter.

Key Takeaways

  • Role: match elements whose text includes a substring.
  • Case: matching is case-sensitive — John ≠ john.
  • Scope: prefer $("li:contains('x')") over bare $(":contains('x')").
  • Extension: jQuery-only — not valid in native CSS APIs.

One line: :contains() finds text substrings inside elements — case-sensitive, jQuery-only, and best when scoped.

Frequently Asked Questions

:contains(text) selects every element whose text content includes the given string — as direct text, inside descendants, or both. $("div:contains('John')") matches a div showing "John Resig" or "Malcom John Sinclair" because "John" appears in that element’s aggregated text.
Yes. Official jQuery docs state the search is case-sensitive. :contains("john") does not match "John Resig". Match the exact casing you expect in the DOM.
Yes. The matching text can appear directly in the element, in any descendant, or a combination. A parent div matches when a nested span holds the search string.
:contains() searches element text content. [name*="value"] searches HTML attribute values such as href or title — not rendered text. Use the right tool for text vs attributes.
No. :contains() is a jQuery extension — not valid CSS. It works inside $() / Sizzle only. document.querySelectorAll(":contains('John')") throws a syntax error.
Prefer scoping: $("#list li:contains('apple')") or $("div.item").filter(":contains('sale')"). Bare $(":contains(text)") scans every element and can be slow on large pages.

Next: :not() Selector

Learn how to exclude elements from a selection with :not().

:not() tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful