How to Replicate jQuery's index() Method in Vanilla JavaScript: Get Element Position Easily

jQuery has long been a go-to library for simplifying DOM manipulation, and its .index() method is a popular tool for finding the position of an element relative to its siblings or a selector. However, as modern JavaScript evolves, many developers are moving away from jQuery to reduce dependencies and leverage native APIs.

In this blog, we’ll break down how jQuery’s .index() works and show you how to replicate its core functionality using vanilla JavaScript. By the end, you’ll have a custom function to get an element’s position effortlessly—no jQuery required.

Table of Contents#

  1. What is jQuery’s index() Method?
    • Overview
    • Key Use Cases
    • Syntax Examples
  2. Why Replicate index() in Vanilla JavaScript?
  3. How jQuery’s index() Works Internally
  4. Replicating index() in Vanilla JavaScript: Step-by-Step
    • Basic Case: Sibling Index
    • Advanced Case: Selector-Based Index
  5. Practical Examples
    • Example 1: Get Sibling Index of a List Item
    • Example 2: Get Index in a Custom Selector
    • Example 3: Edge Case (Element Not in DOM)
  6. Testing the Vanilla JavaScript index() Function
  7. Comparison: jQuery .index() vs. Vanilla getIndex()
  8. Conclusion
  9. References

What is jQuery’s index() Method?#

jQuery’s .index() method returns an integer representing the position of an element relative to a set of elements (either its siblings or a custom selector). It’s incredibly versatile and widely used for tasks like tracking user interactions (e.g., “which tab was clicked?”) or dynamic UI updates.

Key Use Cases#

  • Finding the position of an element among its direct siblings (e.g., a list item in a <ul>).
  • Determining an element’s position relative to a selector (e.g., “is this the 2nd .active element on the page?”).

Syntax Examples#

jQuery’s .index() behaves differently based on how it’s called:

1. No Arguments: Sibling Index#

When called on a DOM element with no arguments, .index() returns the element’s position among its direct sibling elements (ignoring text/comment nodes).

// Returns the index of #target among its sibling elements
const index = $("#target").index(); 

2. With a Selector: Position in Matched Set#

When passed a selector, .index() returns the element’s position relative to all elements matching that selector.

// Returns the index of #target among all .item elements
const index = $("#target").index(".item"); 

Why Replicate index() in Vanilla JavaScript?#

  • Reduce Dependencies: jQuery adds ~30KB to your project. For simple tasks like getting an element’s index, native JavaScript is more efficient.
  • Performance: Native APIs are often faster than jQuery, as they avoid library overhead.
  • Learning Opportunity: Understanding how .index() works under the hood deepens your knowledge of DOM manipulation.

How jQuery’s index() Works Internally#

At a high level, jQuery’s .index() operates in two modes:

Mode 1: Sibling Index (No Arguments)#

  1. Find the element’s parent node.
  2. Collect all direct sibling elements (ignoring text/comment nodes) of the parent.
  3. Return the position of the target element in this collection (index starts at 0).

Mode 2: Selector-Based Index (With Arguments)#

  1. Collect all elements that match the provided selector (e.g., .item).
  2. Return the position of the target element in this collection (index starts at 0).

Replicating index() in Vanilla JavaScript: Step-by-Step#

We’ll build a custom function called getIndex() that mimics both modes of jQuery’s .index(). Let’s break it down.

Step 1: Basic Case – Get Sibling Index#

To replicate the “no arguments” case, we need to:

  • Check if the element has a parent.
  • Get the parent’s direct child elements (ignoring text/comment nodes).
  • Find the element’s position in this list.

Code Implementation#

function getIndex(elementOrSelector, element) {
  // Case 1: No selector provided (return sibling index)
  if (element === undefined) {
    const targetElement = elementOrSelector;
 
    // Validate input: ensure we're working with a DOM element
    if (!(targetElement instanceof Element)) {
      throw new Error("First argument must be a DOM element when no selector is provided.");
    }
 
    // Get the element's parent
    const parent = targetElement.parentNode;
    if (!parent) return -1; // No parent? Return -1
 
    // Get parent's direct child elements (ignores text/comment nodes)
    const siblings = Array.from(parent.children);
 
    // Return the index of the target element in the siblings array
    return siblings.indexOf(targetElement);
  }
 
  // ... (Advanced case code below)
}

Step 2: Advanced Case – Selector-Based Index#

To replicate the “with selector” case, we need to:

  • Collect all elements matching the selector.
  • Find the target element’s position in this collection.

Code Implementation (Add to getIndex())#

function getIndex(elementOrSelector, element) {
  // ... (Basic case code above)
 
  // Case 2: Selector provided (return index in matched set)
  const selector = elementOrSelector;
  const targetElement = element;
 
  // Validate inputs
  if (typeof selector !== "string" || !(targetElement instanceof Element)) {
    throw new Error("First argument must be a selector string, and second must be a DOM element.");
  }
 
  // Collect all elements matching the selector
  const matchedElements = Array.from(document.querySelectorAll(selector));
 
  // Return the index of the target element in the matched set
  return matchedElements.indexOf(targetElement);
}

Practical Examples#

Let’s test getIndex() with real-world scenarios.

Example 1: Get Sibling Index of a List Item#

HTML

<ul id="fruits">
  <li>Apple</li>
  <li>Banana</li>
  <li id="target">Cherry</li> <!-- We want this element's index -->
  <li>Date</li>
</ul>

JavaScript

const target = document.getElementById("target");
const index = getIndex(target); 
console.log(index); // Output: 2 (since indexes start at 0)

Explanation: The parent (<ul>) has 4 <li> children. #target is the 3rd child, so its index is 2.

Example 2: Get Index in a Custom Selector#

HTML

<div class="item">A</div>
<div class="item active">B</div> <!-- Target -->
<div class="item">C</div>
<div class="item active">D</div>

JavaScript

const target = document.querySelector(".active"); // Selects "B"
const index = getIndex(".active", target); 
console.log(index); // Output: 0 (first element in .active set)

Explanation: The selector .active matches 2 elements (B and D). target is the first match, so its index is 0.

Example 3: Edge Case (Element Not in DOM)#

If an element has no parent (e.g., created dynamically but not added to the DOM), getIndex() returns -1:

JavaScript

const orphan = document.createElement("div"); // No parent
console.log(getIndex(orphan)); // Output: -1

Testing the Vanilla JavaScript index() Function#

To ensure getIndex() works reliably, test these scenarios:

ScenarioExpected Output
Element is the first sibling0
Element is the last siblingn-1 (n = number of siblings)
Element has no parent-1
Element not in selector matched set-1

Comparison: jQuery .index() vs. Vanilla getIndex()#

FeaturejQuery .index()Vanilla getIndex()
DependenciesRequires jQueryNone
Size~30KB (jQuery library)~0.2KB (custom function)
PerformanceSlower (library overhead)Faster (native APIs)
Sibling Index SupportYesYes
Selector Index SupportYesYes
Edge Case HandlingHandles rare DOM edge casesHandles common cases (sufficient for most apps)

Conclusion#

Replicating jQuery’s .index() in vanilla JavaScript is surprisingly simple. The getIndex() function we built handles both sibling and selector-based indexing with minimal code, eliminating the need for jQuery.

By using native APIs like parentNode, children, and querySelectorAll, we’ve created a lightweight, performant solution that works for most real-world scenarios. This not only reduces dependencies but also deepens your understanding of DOM manipulation.

References#