jQuery nth-of-type Selector with Mixed Siblings

This article explains how the jQuery :nth-of-type selector behaves when applied to a container holding mixed sibling elements. It outlines the counting algorithm used by the selector, clarifies the difference between :nth-of-type and :nth-child, and provides practical examples demonstrating how jQuery isolates specific HTML tag types regardless of their position in the DOM tree.

The Core Behavior of :nth-of-type

When using jQuery’s :nth-of-type() selector, the count is determined exclusively by the element's tag name (such as p, div, or span), completely ignoring any other sibling elements that have different tag names. Unlike standard position-based selectors, :nth-of-type creates separate, independent index counters for each unique HTML tag type under the same parent element.

If you have a container with an assortment of <h1>, <p>, and <div> tags, selecting p:nth-of-type(2) tells jQuery to scan the parent container, filter for only <p> tags, and select the second <p> element found, regardless of how many other non-paragraph tags appear before or between them.

Mixed Siblings Example

Consider the following HTML structure:

<div class="container">
  <h1>Title</h1>
  <p>First paragraph</p>
  <div>First div</div>
  <span>A span</span>
  <p>Second paragraph</p>
  <div>Second div</div>
</div>

If you execute the following jQuery code:

$('.container p:nth-of-type(2)').css('color', 'red');

jQuery evaluates the siblings as follows:

  1. <h1>Title</h1> — Tag is h1. Skipped.
  2. <p>First paragraph</p> — First p tag encountered (p:nth-of-type(1)).
  3. <div>First div</div> — Tag is div. Skipped.
  4. <span>A span</span> — Tag is span. Skipped.
  5. <p>Second paragraph</p> — Second p tag encountered (p:nth-of-type(2)). Matched.
  6. <div>Second div</div> — Tag is div. Skipped.

The text "Second paragraph" turns red, even though it is physically the fifth child inside .container.

Key Differences: :nth-of-type vs. :nth-child

Understanding this behavior requires distinguishing :nth-of-type from :nth-child:

  • :nth-child(n): Counts every single child element under the parent, regardless of tag type. If you query p:nth-child(2) on the structure above, it checks the second overall child. Since the second child is indeed a <p>, it matches. However, p:nth-child(3) would fail to match anything because the third child is a <div>, not a <p>.
  • :nth-of-type(n): Filters strictly by tag type first. It only increments its counter when encountering the tag specified before the pseudo-class.

Important Caveats with Classes

A common misconception is that :nth-of-type can count by class name, such as .highlight:nth-of-type(2). In CSS and jQuery, "type" strictly refers to the HTML tag name, not the class.

If mixed tags share the same class:

<p class="item">Item 1</p>
<div class="item">Item 2</div>
<p class="item">Item 3</p>

Running $('.item:nth-of-type(1)') will select both the first <p> and the first <div>, because each represents the first element of its respective tag type that also possesses the .item class. To select elements strictly by class position regardless of tag type, jQuery's .eq() method or the :eq() selector should be used instead.