jQuery .contents() vs .children() Explained

This article breaks down the jQuery .contents() and .children() methods, exploring what .contents() does, how both methods traverse the DOM, and their crucial functional differences. Readers will learn how these methods handle text nodes, HTML elements, and iframes, allowing developers to choose the right traversal method for their specific use cases.

Understanding the jQuery .contents() Method

The .contents() method retrieves all immediate children of each element in the matched set. Unlike most DOM traversal methods in jQuery, .contents() does not limit itself strictly to HTML element nodes (like <div>, <p>, or <span>). Instead, it returns:

  • Element nodes: Standard HTML elements.
  • Text nodes: Free text, whitespace, and line breaks directly inside the parent element.
  • Comment nodes: HTML comments located within the element.
  • Iframe documents: The document node inside an <iframe>, provided the iframe follows the same-origin policy.

Because of this behavior, .contents() is the primary jQuery method used to target raw text inside a container or inspect the DOM of an embedded iframe.

Understanding the jQuery .children() Method

The .children() method traverses one single level down the DOM tree to retrieve the immediate child elements of the matched set.

Its defining characteristic is that it filters out everything that is not an element node. Text nodes, whitespace, and comments are entirely ignored. Additionally, .children() accepts an optional selector expression (for example, $('div').children('.active')), allowing developers to narrow down the retrieved child elements immediately.

Key Differences Between .contents() and .children()

While both methods search one level deep into the DOM tree, their scope and capabilities diverge in three main areas:

1. Handling of Text and Comment Nodes

  • .children(): Strictly targets element nodes (nodeType === 1). Any loose text, whitespace, or comments directly inside the parent are discarded.
  • .contents(): Targets all child nodes regardless of type, including element nodes (nodeType === 1), text nodes (nodeType === 3), and comment nodes (nodeType === 8).

2. Built-in Selector Filtering

  • .children([selector]): Accepts an optional selector string to filter elements directly during the traversal.
  • .contents(): Does not accept arguments. To filter the nodes returned by .contents(), developers must chain additional methods like .filter().

3. Iframe Traversal

  • .children(): Cannot penetrate into the document of an <iframe>. Calling .children() on an iframe element yields nothing.
  • .contents(): When called on an <iframe>, it returns the iframe's internal document object, allowing scripts to query and manipulate elements within that frame (e.g., $('iframe').contents().find('body')).

Practical Comparison Example

Consider the following HTML structure:

<div id="container">
    Hello World!
    <!-- This is a comment -->
    <span>Featured Item</span>
</div>

If you query the #container element using both methods:

// Using .children()
const childElements = $('#container').children();
console.log(childElements.length); // Output: 1 (only the <span>)

// Using .contents()
const allContents = $('#container').contents();
console.log(allContents.length);   // Output: 4 (text node, comment, text node, and span)

In this scenario, .children() returns only the single <span> element. Conversely, .contents() captures the leading text node containing "Hello World!", the HTML comment, the whitespace text nodes, and the <span> element.

When to Use Which Method

Use .children() when working exclusively with standard HTML markup, building layout logic, or filtering components by classes or tags.

Use .contents() when accessing or modifying raw text that is not wrapped in an HTML tag, wrapping loose text nodes, stripping comments, or manipulating the contents of a same-origin iframe.