The .has() traversing method filters containers — it keeps elements from the current set that contain at least one matching descendant. This tutorial covers the official nested list demo, the ul/li containment check, comparisons with .find() and .filter(), and DOM element containment.
01
Selector
.has("ul")
02
Parents
Not children
03
Any depth
All descendants
04
DOM node
Contains check
05
vs .find()
Up vs down
06
Since 1.4
Core API
Fundamentals
Introduction
Sometimes you need containers that contain something specific — list items with nested sublists, divs that hold error messages, sections with active tabs inside. The .has() method filters the current set to elements whose descendants match your selector.
Available since jQuery 1.4, .has(selector) or .has(domElement) returns the parent elements from the original collection — not the matching descendants. Think of it as the inverse direction of .find(): find goes down to children; has keeps parents that have those children inside.
Concept
Understanding the .has() Method
Given a jQuery object representing a set of DOM elements, .has(selectorOrElement) tests each element’s descendants. If any descendant matches, that element stays in the result. The returned jQuery object still refers to the same container nodes — just a filtered subset of them.
This is different from .filter(), which tests the elements themselves. $("li").filter(".active") keeps li elements with class active. $("li").has(".active") keeps li elements that contain a descendant with class active — the li itself need not have that class.
💡
Beginner Tip
$("li").find("ul") returns nested ul elements. $("li").has("ul") returns the li parents that wrap those lists. Same DOM, opposite direction.
Foundation
📝 Syntax
General forms of .has:
jQuery
.has( selector )
.has( contained )
Parameters
selector — a string containing a selector expression tested against descendants of each element in the current set.
contained — a DOM element; keeps elements that contain this node as a descendant.
Return value
A new jQuery object containing elements from the current set that have at least one matching descendant.
Official jQuery API nested list example
jQuery
$( "li" ).has( "ul" ).css( "background-color", "red" );
// Red on item 2 only — the li that contains a nested ul
Cheat Sheet
⚡ Quick Reference
Goal
Code
li elements containing a ul
$("li").has("ul")
Divs with error messages inside
$("div.panel").has(".error")
Forms with required fields
$("form").has("[required]")
Get matching descendants (not parents)
$("li").find("ul")
Filter elements by their own class
$("li").filter(".active")
Containment at query time
$("div:has(p)")
Compare
📋 .has() vs .find() vs .filter()
Three methods that change which elements you work with — containment vs descent vs self-match.
.has()
parents
Keep containers with matching descendants
.find()
children
Return descendant matches inside set
.filter()
self
Test current elements — not descendants
Direction
contains?
.has() asks if inside matches exist
Hands-On
Examples Gallery
Examples 1–2 follow the official jQuery API documentation. Use DevTools or the Try-it links to run each snippet in the browser.
📚 Getting Started
Official jQuery demos for descendant containment filtering.
Example 1 — Official Demo: li Elements Containing a ul
Highlight list items that contain a nested sublist — the core official nested-list lesson.
Appended text: "Yes"
ul.has("li") → red .full border class
How It Works
.has("li").length counts how many ul elements contain at least one li. Since every ul in the demo has list items, the answer is Yes and the border class applies.
📈 Practical Patterns
Compare with .find() and .filter(), then target panels with errors.
Example 3 — .has() vs .find() on the Same List
See how parent filtering differs from descendant selection.
.has("ul") → red text on parent li
.find("ul") → blue border on nested ul element
How It Works
Both methods relate to nested lists, but they return different nodes. Use .has() to style or act on the container; use .find() to style the inner match.
Example 4 — .has() vs .filter()
Self-match vs descendant-match on list items with nested active links.
jQuery
$( "#has-active li" ).has( ".active" ).css( "background", "#ffe0e0" );
$( "#filter-active li" ).filter( ".active" ).css( "background", "#e0e0ff" );
// li with active child vs li that IS active
.has(".active") → pink parent li (contains active link)
.filter(".active") → blue li that has class active itself
How It Works
A menu item may contain an active link without being active itself. .has(".active") catches that parent; .filter(".active") only matches when the li element directly has the class.
Example 5 — Highlight Panels That Contain Errors
Real-world pattern: flag form sections with validation messages inside.
The panel divs stay in the result — only those with an error message descendant get the warning class. The error spans themselves are not selected by .has().
Applications
🚀 Common Use Cases
Nested menu items — $("li").has("ul") for items with submenus.
Form sections with errors — $(".section").has(".error").
Tables with checked rows — $("tr").has(":checked").
Cards with images — $(".card").has("img").
Lists with empty inputs — $("form").has("input:blank") (with appropriate selector).
Containment check — if ($("#container").has("#target").length) { ... }.
🧠 How .has() Filters by Containment
1
Start with containers
jQuery object holds candidate parent elements.
Input
2
Search inside each
Test descendants against selector or DOM node.
Descend
3
Keep matches
Parent stays if any descendant matches.
Filter
4
📦
Return & chain
Filtered parent set — push stack for .end().
Important
📝 Notes
Available since jQuery 1.4 — accepts a selector string or DOM element.
Returns container elements from the current set — not matching descendants.
Checks all descendant levels — not limited to direct children.
Related to :has() selector — method form for mid-chain filtering.
Pushes onto jQuery’s internal stack — pair with .end() to restore the previous set.
Empty result returns an empty jQuery object — safe to chain.
Compatibility
Browser Support
.has() has been part of jQuery since 1.4+. It relies on descendant selector matching with no browser-specific behavior beyond jQuery itself.
✓ jQuery 1.4+
jQuery .has()
Supported in jQuery 1.x, 2.x, and 3.x across all modern browsers and IE with supported jQuery builds. Native CSS :has() is separate — jQuery .has() works in older browsers via jQuery's engine.
100%With jQuery loaded
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 in any jQuery project. Use .has() for parent containment; use .find() when you need the inner matches.
Wrap Up
Conclusion
The jQuery .has() method filters the current collection to elements that contain at least one matching descendant. It is the container-focused counterpart to .find() — same tree, opposite direction.
Remember the official nested list lesson: only item 2 gets the red background because it is the sole li wrapping a ul. Use .filter() when the element itself must match; use .has() when something inside it must match.
Use .has() when you need parent/container elements
Pair with .find() mentally — opposite directions
Use for validation UI — highlight sections containing errors
Call .end() after .has() when continuing on the full set
Prefer .has() over manual descendant loops for readability
❌ Don’t
Use .has() when you need the descendant nodes — use .find()
Confuse .has() with .filter() — self vs inside
Expect direct-child-only matching — all depths are searched
Assume CSS :has() and jQuery .has() behave identically in all edge cases
Forget that the returned set is still the original container elements
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about .has()
Keep parents with matching descendants.
5
Core concepts
📦01
.has()
Parents
API
🔍02
.find()
Opposite
Compare
🖼03
.filter()
Self match
Compare
↓04
Depth
Any level
Scope
:has05
:has()
Selector kin
Related
❓ 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 parent/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 ul elements; $('li').has('ul') gives li elements that wrap a ul.
.filter() tests each element in the current set against a selector or callback — the element itself must match. .has() tests descendants inside each element — the parent stays in the result if any child/descendant matches.
Yes, since jQuery 1.4. .has(domElement) keeps elements from the current set that contain the specified DOM node as a descendant. Useful when checking containment against a known element reference.
No. .has() checks all descendants at any depth — grandchildren and deeper included. It is like asking 'does this element contain a match anywhere inside it?' not 'is there a direct child match?'
Both express containment — 'elements that have X inside.' jQuery's :has() works in selector strings at query time — $('div:has(p)'). The .has() method applies the same logic to an existing collection — $('div').has('p'). Prefer .has() mid-chain after .filter() or .find().
Did you know?
jQuery added .has() in version 1.4 alongside .first() and .last(). Before that, developers often wrote $("li").filter(function(){ return $(this).find("ul").length; }) — .has("ul") replaces that verbose pattern with one clear method call.