Lesson 2 of 12

jQuery Selectors

Almost every line of jQuery starts by selecting something: “find the menu”, “find every price”, “find the checked boxes”. jQuery selectors use the same syntax as CSS, so if you know CSS Selectors you already know most of this lesson. Here you will practise the common patterns, learn how to check whether anything matched, and see the modern way to pick one element out of many.

CSS selectors work as they are

Pass any valid CSS selector string to $(). jQuery hands most of them to the browser’s own fast querySelectorAll() and wraps the result.

SelectorSelects
$('#cart')The element with id="cart"
$('.price')Every element with the class price
$('li')Every <li> element
$('#menu a')Links anywhere inside #menu (descendants)
$('ul > li')Only direct <li> children of a list
$('h2, h3')All <h2> and <h3> elements (a group)
$('input[type="email"]')Inputs whose type attribute is email
$('a[href^="https"]')Links whose href starts with https
$('input:checked')Ticked checkboxes and selected radio buttons
$('li:not(.sold-out)')List items without the class sold-out

Try these jQuery selectors in the playground below. Each button runs a different selector and highlights what it found, along with the count.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Selector playground</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
    li { padding: 2px 6px; }
    .hit { background: #ffe58a; outline: 2px solid #e0a800; }
    button { margin: 2px; }
  </style>
</head>
<body>
  <ul id="cities">
    <li class="south" data-state="TN">Chennai</li>
    <li class="south" data-state="KA">Bengaluru</li>
    <li class="north" data-state="DL">Delhi</li>
    <li class="south capital" data-state="KL">Thiruvananthapuram</li>
    <li class="west" data-state="MH">Mumbai</li>
  </ul>
  <p>
    <button type="button" data-sel="li">li</button>
    <button type="button" data-sel=".south">.south</button>
    <button type="button" data-sel=".south.capital">.south.capital</button>
    <button type="button" data-sel="li:not(.south)">li:not(.south)</button>
    <button type="button" data-sel='[data-state="KA"]'>[data-state="KA"]</button>
    <button type="button" data-sel=".east">.east</button>
  </p>
  <p id="result">Click a selector.</p>

  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <script>
$('button[data-sel]').on('click', (event) => {
  const selector = $(event.currentTarget).attr('data-sel');

  $('#cities li').removeClass('hit');        // clear old highlights
  const $found = $('#cities').find(selector).addClass('hit');

  $('#result').text(`$('${selector}') matched ${$found.length} element(s).`);
});
  </script>
</body>
</html>

Try .east: nothing matches, the count is 0, and there is no error. That is handy, but it can also hide typos. When something “does nothing”, check .length first.

Checking whether jQuery selectors matched

Because a jQuery object always exists, if ($('#banner')) is always true – an empty object is still an object. Test the length instead:

if ($('#banner').length) {
  // the banner exists on this page, so it is safe to set it up
  $('#banner').addClass('ready');
}

// Plain JavaScript equivalent
const banner = document.querySelector('#banner');
if (banner) {
  banner.classList.add('ready');
}

Picking one element from many

Older tutorials use jQuery-only pseudo-selectors such as :first, :last, :eq(2), :even and :odd. These were deprecated in jQuery 3.4 because the browser cannot run them natively. Use the matching methods instead, which work on any set:

  • .first() and .last() – the first or last element of the set.
  • .eq(index) – the element at a zero-based position; .eq(-1) counts from the end.
  • .even() and .odd() – elements at even or odd indexes (added in jQuery 3.5).
  • .filter(selector) – keep only the elements that also match another selector.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Rows with .even(), .eq() and .filter()</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
    table { border-collapse: collapse; }
    td, th { border: 1px solid #ccc; padding: 6px 10px; }
    .zebra { background: #eef4ff; }
    .top { font-weight: bold; color: #0a7a3d; }
  </style>
</head>
<body>
  <table>
    <thead><tr><th>Item</th><th>Price (₹)</th></tr></thead>
    <tbody>
      <tr><td>Filter coffee</td><td>30</td></tr>
      <tr><td>Medu vada</td><td>40</td></tr>
      <tr><td>Rava dosa</td><td>90</td></tr>
      <tr><td>Lemon rice</td><td>70</td></tr>
    </tbody>
  </table>
  <button id="stripe" type="button">Check prices</button>
  <p id="note"></p>

  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <script>
$('#stripe').on('click', () => {
  const $rows = $('tbody tr');

  // Index 0, 2, … → the 1st and 3rd rows on screen
  $rows.even().addClass('zebra');

  // Third row (index 2)
  $rows.eq(2).find('td').first().append(' ⭐');

  // Rows whose price cell is above 50
  const $costly = $rows.filter((i, row) => Number($(row).find('td').last().text()) > 50);
  $costly.addClass('top');

  $('#note').text(`${$costly.length} items cost more than ₹50.`);
});
  </script>
</body>
</html>

Watch out: Indexes start at 0. So .even() selects the 1st, 3rd and 5th rows you see – which humans would call “odd” rows. CSS :nth-child(odd) counts from 1 and selects the same rows. Mixing the two systems is a classic source of off-by-one bugs.

Searching inside an element

To search only inside one part of the page, select the container and call .find() (more in jQuery Traversing): $('#cart').find('.price'). You may also see the two-argument form $('.price', '#cart'), which does the same thing. Searching inside a container is clearer and avoids touching similar elements elsewhere on the page.

If you will use a selection several times, store it in a variable instead of asking jQuery to search again. Many developers start such names with $, as in const $menu = $('#menu');, as a reminder that it holds a jQuery object, not a plain element.

jQuery-only selectors

A few jQuery selectors are not part of CSS, such as :visible, :hidden and :input. They are useful – :visible finds elements that currently take up space on the page – but the browser cannot run them natively, so jQuery must check each element itself. That is slower on large pages and means the selector would fail in plain querySelectorAll().

The recommended pattern is to select with a normal CSS selector first, then narrow the set: write $('.panel').filter(':visible') rather than $('.panel:visible'). The result is the same, but the first step stays fast.

Ids with special characters

CSS gives special meaning to characters such as ., : and #. If an id contains one – for example id="order.42" – the selector $('#order.42') looks for an element with id order and class 42. Use $.escapeSelector() to escape such values, especially when they come from data: $('#' + $.escapeSelector('order.42')).

Tip: You can also wrap elements you already have: $(element) turns a DOM element (for example event.currentTarget) into a jQuery object. To go the other way, $menu[0] or $menu.get(0) gives you the plain DOM element.

Further reading

Key takeaways

  • $() accepts any CSS selector: id, class, tag, attribute, :checked, :not() and groups.
  • A jQuery object is never null – check .length to see if anything matched.
  • Use .first(), .last(), .eq(), .even(), .odd() and .filter() instead of the deprecated :first, :eq() and :odd pseudo-selectors.
  • Indexes start at 0, so .even() picks the 1st, 3rd, 5th… elements.
  • Use .find() to search inside a container, and store repeated selections in a $-named variable.

Quick quiz

Check what you learned – pick an answer.

1. What does if ($('#popup')) { … } do when there is no #popup on the page?

2. Which is the jQuery 4-friendly way to select the third list item?

3. Which selector finds only links whose href starts with "https"?

Practice exercise

In the price table, use .last() to make the last row bold, and use .filter() to give every row whose price is below ₹50 a green background. Show how many cheap items there are in a paragraph.

Show a hint

Number($(row).find('td').last().text()) gives the price of a row inside a .filter() callback.

Show the solution
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Exercise: selectors</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
    table { border-collapse: collapse; }
    td, th { border: 1px solid #ccc; padding: 6px 10px; }
    .zebra { background: #eef4ff; }
    .top { font-weight: bold; color: #0a7a3d; }
    .cheap { background: #dff5e3; }
  </style>
</head>
<body>
  <table>
    <thead><tr><th>Item</th><th>Price (₹)</th></tr></thead>
    <tbody>
      <tr><td>Filter coffee</td><td>30</td></tr>
      <tr><td>Medu vada</td><td>40</td></tr>
      <tr><td>Rava dosa</td><td>90</td></tr>
      <tr><td>Lemon rice</td><td>70</td></tr>
    </tbody>
  </table>
  <button id="stripe" type="button">Check prices</button>
  <p id="note"></p>

  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <script>
$('#stripe').on('click', () => {
  const $rows = $('tbody tr');
  $rows.last().css('font-weight', 'bold');

  const $cheap = $rows.filter((i, row) => Number($(row).find('td').last().text()) < 50);
  $cheap.addClass('cheap');

  $('#note').text(`${$cheap.length} items cost less than ₹50.`);
});
  </script>
</body>
</html>

Progress is saved in this browser only.