Any CSS selector works
$() hands your selector to the browser's own selector engine, so anything you can write in a stylesheet works. Here are the everyday ones:
<div id="shop">
<h2 class="title">Fruit</h2>
<ul>
<li class="fruit" data-price="40">Apple</li>
<li class="fruit sale" data-price="10">Banana</li>
<li class="fruit" data-price="90">Mango</li>
</ul>
<a href="https://example.com">Supplier</a>
<a href="/about/">About</a>
</div>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
console.log("#shop ", $("#shop").length);
console.log(".fruit ", $(".fruit").length);
console.log("li ", $("li").length);
console.log(".fruit.sale ", $(".fruit.sale").text());
console.log("#shop li ", $("#shop li").length);
console.log("ul > li ", $("ul > li").length);
console.log("[data-price] ", $("[data-price]").length);
console.log("[data-price='90']", $("[data-price='90']").text());
console.log("a[href^=http]", $("a[href^='http']").text());
</script>#shop 1
.fruit 3
li 3
.fruit.sale Banana
#shop li 3
ul > li 3
[data-price] 3
[data-price='90'] Mango
a[href^=http] SupplierA quick reminder of what each does:
#shopselects by id; ids should be unique, so this finds at most one..fruitselects by class..fruit.sale(no space) means elements with both classes.liselects by tag name.#shop li(a space) meanslielements anywhere inside#shop: descendants.ul > limeanslielements that are direct children of aul.[data-price]selects elements that have that attribute;[data-price='90']requires that value.a[href^='http']matches links whosehrefstarts withhttp. Use$=for "ends with" and*=for "contains".
Selecting several groups
A comma combines selectors, exactly as in CSS:
<h1>Heading</h1>
<h2>Sub heading</h2>
<p class="lead">Intro</p>
<p>Body</p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("h1, h2, .lead").css("color", "teal");
console.log($("h1, h2, .lead").length, "elements coloured");
</script>3 elements colouredThe result is one jQuery object with the elements in document order, not the order you listed the selectors.
Pseudo-classes
Standard CSS pseudo-classes are very useful for forms and lists:
<ul id="steps">
<li>One</li><li>Two</li><li>Three</li><li>Four</li><li>Five</li>
</ul>
<label><input type="checkbox" checked> Email me</label>
<label><input type="checkbox"> Text me</label>
<input type="text" disabled value="locked">
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
console.log("first-child :", $("#steps li:first-child").text());
console.log("last-child :", $("#steps li:last-child").text());
console.log("nth-child(2n):", $("#steps li:nth-child(2n)").text());
console.log("not(:first-child):", $("#steps li:not(:first-child)").length);
console.log("checked :", $("input:checked").length);
console.log("disabled :", $("input:disabled").val());
</script>first-child : One
last-child : Five
nth-child(2n): TwoFour
not(:first-child): 4
checked : 1
disabled : locked:nth-child(2n) picks every second item (the even positions, counting from 1). :not() removes matches. :checked and :disabled reflect the current state of form controls, so they are perfect for reading forms.
jQuery's own selectors
jQuery also understands a few selectors that are not part of CSS. You will see them in older code:
<p>Visible text</p>
<p style="display:none">Hidden text</p>
<div class="card"><img src="" alt=""></div>
<div class="card">No image</div>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
console.log(":visible ", $("p:visible").length);
console.log(":hidden ", $("p:hidden").text());
console.log(":contains ", $("p:contains('Visible')").length);
console.log(":has(img) ", $(".card:has(img)").length);
</script>:visible 1
:hidden Hidden text
:contains 1
:has(img) 1:visibleand:hiddencheck whether an element takes up space on the page.:contains('text')matches elements whose text includes that string (case-sensitive).:has(img)matches elements that contain animg. Modern browsers now support:has()in CSS too.
These work, but because jQuery has to check them in JavaScript, they are slower than standard selectors, especially on large pages. A good habit is to select with a fast CSS selector first and then filter, which the next lesson shows. You may also see :first, :last, :eq(2), :even and :odd in old code. They still work in jQuery 4 but have been deprecated since jQuery 3.4; use the methods .first(), .last(), .eq(), .even() and .odd() instead.
Searching inside an element
Often you want to find things inside one part of the page, such as the form the user is working in. Use .find():
<form id="login"><input name="email"><input name="password" type="password"></form>
<form id="search"><input name="q"></form>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
const $login = $("#login");
console.log("inputs in #login:", $login.find("input").length);
console.log("same with context:", $("input", $login).length);
console.log("all inputs:", $("input").length);
</script>inputs in #login: 2
same with context: 2
all inputs: 3$("input", $login) passes a context as the second argument; it does the same as $login.find("input"). Most people find .find() easier to read.
Special characters in ids and classes
If an id contains characters that mean something in CSS, such as a dot or a colon, escape them or the selector breaks. $.escapeSelector() does it for you:
<p id="price.total">250</p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
console.log("unescaped:", $("#price.total").length);
console.log("escaped:", $("#" + $.escapeSelector("price.total")).text());
</script>unescaped: 0
escaped: 250Without escaping, #price.total means "id price with class total", which does not exist.
Common mistakes
- Forgetting the
#or.:$("cart")looks for a<cart>element. - Adding a space by accident:
.fruit .sale(descendant) is not.fruit.sale(both classes). - Using duplicate ids.
$("#x")returns only the first; use a class for repeated elements. - Relying on slow jQuery-only selectors in loops on large pages.
Exercise
Using the shop example from the start of this lesson, log the names of all fruits whose data-price is not 90, using one selector.
Show one possible answer
console.log($(".fruit:not([data-price='90'])").text());The output is AppleBanana. :not() accepts any selector, including attribute selectors.
Key points
- $() accepts any CSS selector the browser understands: #id, .class, tag, [attribute], descendants, :nth-child() and more.
- Combine selectors with a comma to select several groups at once.
- jQuery adds a few extra selectors, such as :visible, :hidden, :contains() and :has(), but they are slower than plain CSS selectors.
- To search inside one element, use $(parent).find("selector") rather than repeating a long selector.