Himanshu SharmaSoftware engineer
Let’s talk

jQuery · Lesson 6 of 45

Filtering a selection

Narrow a jQuery selection with .first(), .last(), .eq(), .even(), .odd(), .filter(), .not(), .has(), .slice() and check it with .is().

12 minSelecting elementsUpdated 23 October 2026

By the end of this lessonStart from a broad selection and narrow it to exactly the elements you need, using positions, selectors or your own test function.

Why filter?

Selectors are good at finding a kind of element. Often, though, you want a particular one: the first row, every other row, the items above a price. jQuery's filtering methods take a selection and return a new, smaller jQuery object. Because they return a jQuery object, you can keep chaining.

Filtering by position

html
<ul>
  <li>Monday</li><li>Tuesday</li><li>Wednesday</li><li>Thursday</li><li>Friday</li>
</ul>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  const $days = $("li");
  console.log("first   ", $days.first().text());
  console.log("last    ", $days.last().text());
  console.log("eq(2)   ", $days.eq(2).text());
  console.log("eq(-2)  ", $days.eq(-2).text());
  console.log("even    ", $days.even().text());
  console.log("odd     ", $days.odd().text());
  console.log("slice(1,3)", $days.slice(1, 3).text());
</script>
result
first    Monday
last     Friday
eq(2)    Wednesday
eq(-2)   Thursday
even     MondayWednesdayFriday
odd      TuesdayThursday
slice(1,3) TuesdayWednesday
  • Positions count from 0: .eq(0) is the first element, .eq(2) the third.
  • Negative numbers count from the end: .eq(-1) is the last.
  • .even() keeps positions 0, 2, 4 (the 1st, 3rd and 5th items); .odd() keeps 1, 3. This is the opposite of what the names suggest if you count from one, so check the output above.
  • .slice(start, end) keeps a range; end is not included.

A common use is striping a table:

html
<table>
  <tr><td>Asha</td></tr><tr><td>Ben</td></tr><tr><td>Chen</td></tr><tr><td>Dev</td></tr>
</table>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  $("tr").odd().css("background", "#e0f2fe");
</script>
result
Asha
Ben
Chen
Dev

(Today a CSS rule, tr:nth-child(even), is the better tool for plain striping. jQuery filtering is useful when the condition depends on data.)

Filtering by selector

.filter(selector) keeps elements that match; .not(selector) removes them:

html
<ul>
  <li class="done">Buy milk</li>
  <li>Call Ravi</li>
  <li class="done">Pay rent</li>
  <li>Book tickets</li>
</ul>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  const $tasks = $("li");
  console.log("done:", $tasks.filter(".done").length);
  console.log("to do:", $tasks.not(".done").text());
</script>
result
done: 2
to do: Call RaviBook tickets

The difference from a longer selector such as $("li.done") is that you can start from a selection you already have, perhaps passed into a function, and narrow it in several ways.

Filtering with your own test

When the condition is not something a selector can express, pass a function to .filter(). It runs once per element with two arguments, the index and the plain DOM element. Return true to keep the element:

html
<ul>
  <li data-price="40">Apple</li>
  <li data-price="120">Cherries</li>
  <li data-price="10">Banana</li>
  <li data-price="90">Mango</li>
</ul>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  const $expensive = $("li").filter(function (index, element) {
    return Number($(element).attr("data-price")) > 50;
  });
  $expensive.css("font-weight", "bold");
  console.log($expensive.length, "items over 50:", $expensive.text());
</script>
result
2 items over 50: CherriesMango

Inside the function, this also refers to the current element, so you will often see $(this) used instead of $(element) in older code.

Keeping elements that contain something

.has(selector) keeps elements that have a matching descendant:

html
<div class="post"><h3>Post one</h3><img src="" alt="photo"></div>
<div class="post"><h3>Post two</h3></div>
<div class="post"><h3>Post three</h3><img src="" alt="photo"></div>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  const $withImages = $(".post").has("img");
  console.log($withImages.find("h3").text());
</script>
result
Post onePost three

Asking a yes or no question

.is() does not return a selection. It returns true if at least one element matches, otherwise false. It is ideal inside if statements:

html
<input type="checkbox" id="terms">
<p id="box" class="warning">Check the terms first.</p>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  console.log("checked?", $("#terms").is(":checked"));
  $("#terms").prop("checked", true);
  console.log("checked now?", $("#terms").is(":checked"));
  console.log("is a warning?", $("#box").is(".warning"));
  console.log("is visible?", $("#box").is(":visible"));
</script>
result
checked? false
checked now? true
is a warning? true
is visible? true

Going back with .end() and .addBack()

Each filter creates a new selection and remembers the previous one. .end() returns to it, which lets one chain style two groups:

html
<ul><li>One</li><li>Two</li><li>Three</li></ul>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  $("li")
    .css("color", "gray")
    .first().css("color", "green").end()
    .last().css("color", "red");

  console.log($("li").map((i, el) => el.style.color).get().join(", "));
</script>
result
green, gray, red

.addBack() does the opposite: it adds the previous selection to the current one. Use both sparingly; long chains that jump back and forth are hard to read.

Common mistakes

  • Counting from 1. .eq(1) is the second element.
  • Expecting .is() to return elements. It returns true or false.
  • Forgetting to return a value from a .filter() function, which drops every element.
  • Using deprecated selectors such as :eq(1) or :odd inside the selector string instead of the methods.

Exercise

From a list of five li items with numbers as text (3, 8, 15, 4, 23), select those greater than 5 and give them the class big. Log how many were selected.

Show one possible answer
html
<ul><li>3</li><li>8</li><li>15</li><li>4</li><li>23</li></ul>

<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
  const $big = $("li").filter(function () {
    return Number($(this).text()) > 5;
  }).addClass("big");
  console.log($big.length);
</script>
result
3

It logs 3 (8, 15 and 23).

Key points

  • Filtering methods return a new, smaller jQuery object, so you can keep chaining.
  • .first(), .last(), .eq(n), .even(), .odd() and .slice() filter by position, counting from 0.
  • .filter() keeps elements that match a selector or a function; .not() removes them; .has() keeps elements containing a match.
  • .is() answers a yes or no question about a selection and returns true or false.

Check yourself

1. Which item does $("li").eq(1) select?
2. What does $("li").eq(-1) select?
3. What does .filter(function (i, el) { ... }) keep?
4. What does $("input").is(":checked") return?