jQuery .has() Method

Beginner
⏱️ 10 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Has descendant

What You’ll Learn

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

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.

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.

📝 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

⚡ Quick Reference

GoalCode
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)")

📋 .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

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.

jQuery
$( "li" ).has( "ul" ).css( "background-color", "red" );
Try It Yourself

How It Works

Only item 2 wraps a ul among its descendants. .has("ul") keeps that li parent — the nested ul itself is not returned.

Example 2 — Official Demo: Does the ul Contain an li?

Check containment and add a border class — official interactive demo pattern.

jQuery
$( "ul" ).append( " " +
  ( $( "ul" ).has( "li" ).length ? "Yes" : "No" ) +
  " " );
$( "ul" ).has( "li" ).addClass( "full" );
Try It Yourself

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.

jQuery
$( "#has-demo li" ).has( "ul" ).css( "color", "red" );
$( "#find-demo li" ).find( "ul" ).css( "border", "2px solid blue" );

// .has() → li parents | .find() → ul descendants
Try It Yourself

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
Try It Yourself

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.

jQuery
$( ".panel" )
  .has( ".error" )
  .addClass( "has-error" );
Try It Yourself

How It Works

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().

🚀 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 checkif ($("#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().

📝 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.

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 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
.has() Universal

Bottom line: Safe in any jQuery project. Use .has() for parent containment; use .find() when you need the inner matches.

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.

💡 Best Practices

✅ Do

  • 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

Key Takeaways

Knowledge Unlocked

Five things to remember about .has()

Keep parents with matching descendants.

5
Core concepts
🔍 02

.find()

Opposite

Compare
🖼 03

.filter()

Self match

Compare
04

Depth

Any level

Scope
:has 05

: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.

Back to jQuery Traversing

Explore more DOM traversal methods as the collection grows.

Traversing hub →

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.

6 people found this page helpful