jQuery / Selector / :nth-child() - Select Sibling Positions with an+b
jQuery's :nth-child(an+b) selects element siblings at positions matching a formula, counting from one within each parent. p:nth-child(2) means a p that is the second element child, rather than the second p. Use :nth-of-type(2) for the second sibling p, or .eq(1) for the second element of an already selected set.
Count from one and include other element types
The :nth-child() documentation follows CSS sibling-position rules. Counting restarts for each parent and includes elements of other tags. Whitespace text and comments are not elements and do not count. Hidden elements still occupy positions when they remain in the document, so visible order alone is insufficient.
If a parent contains h2, p, p, then p:nth-child(1) is empty and p:nth-child(2) selects its first p. It does not collect p elements before numbering them. Use the direct-child combinator > to constrain the scope as the example does.
Read an+b and common formulas
In the CSS definition of an+b, a and b are integers, and n takes nonnegative integers such as 0, 1 and 2. Only positive resulting positions can match. Zero and negative positions select nothing. -n+3 yields 3, 2, 1, meaning the first three element positions; it does not count backward from the end.
| Condition | Positions | Meaning |
|---|---|---|
| 2 | 2 | Second element under each parent |
| 2n or even | 2, 4, 6, … | Even positions |
| 2n+1 or odd | 1, 3, 5, … | Odd positions |
| 3n+1 | 1, 4, 7, … | Every third position from one |
| -n+3 | 1, 2, 3 | First three element positions |
Adding p before the condition keeps only p elements at those positions. If the fourth child is span, p:nth-child(2n) excludes it; it does not skip that span and renumber a later p as fourth.
Complete example with mixed tags
Save all this code as UTF-8 in nth-child-demo.html and open it in a browser. No installation is required, but loading the official jQuery file from its Content Delivery Network (CDN) requires internet. The code uses 4.0.0; formulas, insertion, reset and comparison snippets were executed with both 3.7.1 and 4.0.0.
A contains h2, p, p, span, p, while B contains h2, p, p, p. The result lists p IDs so you can compare matches with tag positions.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Sibling positions and formulas</title>
<style>
body { font: 16px/1.6 sans-serif; margin: 24px; }
.group { border: 1px solid #aaa; padding: 12px; margin: 12px 0; }
.group > * { display: block; margin: 6px 0; padding: 6px; }
.group > .marked { background: #fff0b3; outline: 2px solid #b56b00; }
button, select { padding: 8px; margin: 4px; }
</style>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
</head>
<body>
<h1>Sibling positions and formulas</h1>
<div id="groups">
<section class="group" id="group-a">
<h2>A heading</h2>
<p id="a1">A paragraph 1</p>
<p id="a2">A paragraph 2</p>
<span>A note</span>
<p id="a3">A paragraph 3</p>
</section>
<section class="group" id="group-b">
<h2>B heading</h2>
<p id="b1">B paragraph 1</p>
<p id="b2">B paragraph 2</p>
<p id="b3">B paragraph 3</p>
</section>
</div>
<label for="rule">Formula:</label>
<select id="rule">
<option value="2">2</option>
<option value="2n">2n (even)</option>
<option value="2n+1">2n+1 (odd)</option>
<option value="3n+1">3n+1</option>
<option value="-n+3">-n+3</option>
</select>
<button type="button" id="prepend">Prepend notice to A</button>
<button type="button" id="reset">Reset</button>
<output id="result" aria-live="polite"></output>
<script>
$(function () {
function refresh() {
$("#groups > .group > p").removeClass("marked");
const rule = $("#rule").val();
const $chosen = $("#groups > .group > p:nth-child(" + rule + ")");
$chosen.addClass("marked");
const ids = $chosen.map((_, item) => item.id).get().join(", ");
$("#result").text(`${ids || "none"} | ${$chosen.length}`);
}
$("#rule").on("change", refresh);
$("#prepend").on("click", function () {
if (!$("#extra").length) {
$("#group-a").prepend('<div id="extra">Notice</div>');
}
refresh();
});
$("#reset").on("click", function () {
$("#extra").remove();
$("#rule").val("2");
refresh();
});
refresh();
});
</script>
</body>
</html>
The initial formula is 2. The second element in each group is its first p, highlighting a1 and b1:
a1, b1 | 2
- Choose 2n for
a1, b1, b3 | 3. A's fourth element is span and fails the p condition. - 2n+1 yields
a2, a3, b2 | 3. The first element in each group is h2 and is excluded. - 3n+1 yields
b3 | 1. A's first and fourth children are h2 and span; only B's fourth is p. - -n+3 yields
a1, a2, b1, b2 | 4: p elements among each parent's first three element children. - Press Reset, then Prepend notice to A. The new leading div makes A's second child h2, leaving
b1 | 1for formula 2. Repeated clicks do not add duplicates. - Reset removes only the extra div, restores formula 2 and queries again. Original content and
a1, b1 | 2return.
Compare :nth-of-type() and .eq()
After Reset, run this fragment in the developer console. :nth-of-type() counts siblings sharing the tag, whereas .eq() counts an already selected set from zero.
const ids = $set => $set.map((_, item) => item.id).get().join(", ");
console.log(ids($("#groups > .group > p:nth-child(2)")));
console.log(ids($("#groups > .group > p:nth-of-type(2)")));
console.log(ids($("#groups > .group > p").eq(1)));
a1, b1
a2, b2
a2
The first line returns a1 and b1, second element children that are p. The second returns a2 and b2, the second p under each parent. The last returns only a2 at index 1 in the combined p set. A negative .eq() index counts from the end of that set and differs from the -n+3 formula.
Dynamic documents and unexpected results
Selections do not automatically reflect document changes. A set storing a1 and b1 before insertion keeps those elements afterward. To match current sibling positions, query again as refresh does and clear previous highlights.
For empty results, check for zero or nonexistent positions, the actual tag at that position, and intervening headings, notices or hidden elements. With tables, inspect intermediate parents such as tbody in the Document Object Model (DOM). If nothing responds, first check jQuery loading in Network and errors in Console.




