.has(selector|element) (since jQuery 1.4) reduces the matched set to elements that contain a matching descendant. The result is the containers — not the inner matches.
Remember
// Official pattern — li that contain a nested ul
$("li").has("ul");
// Yes/No: does the ul contain any li?
$("ul").has("li").length ? "Yes" : "No";
// Same idea as :has() at query time
$("li:has(ul)");
// Not the same as .find() (returns descendants)
$("li").find("ul");
Select candidates, then keep only those that contain a match inside.
Select the candidate containers — e.g. $("li") or $("div.card").
Call .has("selector") or .has(domElement).
Remember: the result is a subset of the original set.
Chain methods on those containers — .text(), .addClass(), …
Use .find() instead when you need the inner matches.
Piece
Required?
Role
Matched set
Yes
Candidate containers
selector
One of
Descendant pattern to look for
element
One of
Specific DOM node that must be inside
Depth
—
Any depth (not just direct children)
Return value
—
New jQuery set (subset of parents)
Pseudocode
Pseudocode
call $(candidates).has(target)
result = empty set
for each candidate in the matched set:
look inside candidate for descendants
if any descendant matches target (selector or element):
add candidate to result
return result
→ containers, not the inner matches
Reference
Cheat Sheet
Keep these differences next to .find() and .filter().
Topic
Detail
Syntax
.has(selector|element)
Since
jQuery 1.4
Returns
Containers from the current set
Depth
Any descendant depth
vs .find()
Parents vs descendants
vs .filter()
Inside vs the element itself
vs :has()
Method mid-chain vs selector string
Official demo
$("li").has("ul")
Try it
Live Preview
Mark li that contain a nested ul, or compare .has() with .find().
Only item 2 contains a nested list. .has("ul") keeps that li; .find("ul") returns the inner ul.
list item 1
list item 2
list item 2-a
list item 2-b
list item 3
list item 4
Result
Ready — pick an action and click Run.
Code
jQuery Examples
Short, copy-ready snippets. Use Try It Yourself for a live editor.
Example 1 — Official $("li").has("ul")
Mark the list item that contains a nested list (CSS-free).
Target. Grab a known DOM node with getElementById.
Has. Keep boxes that contain that exact node.
Mark. Only the true container is labeled.
Use. Handy when you already hold an element reference.
Edge Cases & Pitfalls
Check these when .has() returns an empty set.
result
You get parents, not children
$("li").has("ul") returns li nodes. To style the nested ul, use .find("ul").
self
The element itself does not count
$("ul").has("ul") looks for a nested ul. A lone outer ul does not match itself.
depth
Any depth counts
Grandchildren match too. If you need only direct children, combine with .children() logic instead.
scope
Start from the right set
$("li").has("ul") and $("div").has("ul") answer different questions — choose the candidate containers carefully.
Compatibility
Browser Support
.has() is a core jQuery traversing method since 1.4. It works in every browser that runs your loaded jQuery version. The related CSS :has() selector is separate and depends on browser CSS support.
✓ Stable · jQuery 1.4+
jQuery .has()
Universal across jQuery-supported browsers. Prefer .has() mid-chain; use :has() in selector strings when the browser/CSS engine supports it.
1.4+jQuery since
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
.has()Universal
Bottom line: Safe for everyday UI. Remember it returns containers — use .find() when you need the inner matches.
Analysis
Performance Notes
Approach
Cost
Best for
Scoped $("#menu li").has("ul")
Cheap
Menus, cards, local trees
$("li").has("ul")
Cheap–moderate
Page-wide parent filtering
Deep trees + broad candidates
Moderate
Narrow the set before .has()
Scope candidates first. .has() must look inside each element, so a smaller starting set is faster on large pages.
Remember
Key Takeaways
Role: keep elements that contain a matching descendant.
Result: containers from the current set — not the inner matches.
vs .find(): parents vs descendants.
Also: accept a selector or a DOM element since 1.4.
One line:.has() answers “which of these contain X?” — use .find() when you want X itself.
Frequently Asked Questions
.has() reduces the current jQuery collection to elements that contain at least one descendant matching a selector or DOM element. It returns the container elements — not the matching descendants themselves.
.find() returns the descendant elements that match. .has() returns the ancestors from the current set that contain such descendants. $("li").find("ul") gives nested uls; $("li").has("ul") gives li elements that wrap a ul.
.filter() tests each element in the current set — the element itself must match. .has() tests descendants inside each element — the parent stays if any descendant matches.
Yes, since jQuery 1.4. .has(domElement) keeps elements from the current set that contain that DOM node as a descendant.
No. .has() checks all descendants at any depth — grandchildren and deeper included.
Both mean “elements that have X inside.” $("div:has(p)") does it at query time; $("div").has("p") applies the same idea to an existing collection.