JavaScript DOM: find element index in container

I need to find the index of an element inside its container by reference to the object. Oddly enough, I cannot find an easy way. No jQuery please - just the DOM.

UL LI LI LI - my index is 2 LI 

Yes, I could assign identifiers to each element and iterate over all nodes according to ID, but this seems like a bad solution. Is there nothing better?

So, let's say I have an object reference for the third LI, as in the above example. How to find out what is index 2?

Thank.

+58
javascript dom html parent-child
Aug 01 2018-12-12T00:
source share
13 answers

You can use Array.prototype.indexOf . To do this, we need to somewhat "distinguish" the HTMLNodeCollection from the true Array . For example:

 var nodes = Array.prototype.slice.call( document.getElementById('list').children ); 

Then we could just call:

 nodes.indexOf( liNodeReference ); 

Example:

 var nodes = Array.prototype.slice.call( document.getElementById('list').children ), liRef = document.getElementsByClassName('match')[0]; console.log( nodes.indexOf( liRef ) ); 
 <ul id="list"> <li>foo</li> <li class="match">bar</li> <li>baz</li> </ul> 
+74
Aug 01 2018-12-12T00:
source share

Update 2017

The original answer below assumes that the OP wants to include non-empty text node and other node types as well as elements. Now it is not clear to me from the question whether this is a valid assumption.

Assuming you just need the index of the element, previousElementSibling now well supported (which was not in 2012) and is now the obvious choice. The following (the same as some other answers here) will work in all the main things except IE <= 8.

 function getElementIndex(node) { var index = 0; while ( (node = node.previousElementSibling) ) { index++; } return index; } 

Original answer

Just use previousSibling until you hit null . I assume that you want to ignore text nodes for spaces only; if you want to filter out other nodes, then configure accordingly.

 function getNodeIndex(node) { var index = 0; while ( (node = node.previousSibling) ) { if (node.nodeType != 3 || !/^\s*$/.test(node.data)) { index++; } } return index; } 
+41
Aug 01 '12 at 15:37
source share

Here's how I do it (version 2018?) :

 const index = [...el.parentElement.children].indexOf(el); 

Tadaaaam. And if you also want to consider the source text nodes, you can do this instead:

 const index = [...el.parentElement.childNodes].indexOf(el); 

I am distributing the children to the array as they are an HTMLCollection (therefore they do not work with indexOf).

Be careful that you use Babel or that browser coverage is enough for what you need to achieve (thoughts on the distribution operator, which is basically Array.from behind the scenes).

+15
Apr 04 '18 at 8:59
source share
 Array.prototype.indexOf.call(this.parentElement.children, this); 

Or use the let statement.

+12
Jan 18 '16 at 21:41
source share

For simple elements, this can be used to find the index of an element among its sibling elements:

 function getElIndex(el) { for (var i = 0; el = el.previousElementSibling; i++); return i; } 

Note that previousElementSibling not supported on IE <9.

+9
Dec 17 '14 at 8:49
source share

You can use this to find the index of an element:

Array.prototype.indexOf.call(yourUl, yourLi)

This, for example, registers all indexes:

 var lis = yourList.getElementsByTagName('li'); for(var i = 0; i < lis.length; i++) { console.log(Array.prototype.indexOf.call(lis, lis[i])); }​ 

JSFIDDLE

+8
Aug 01 2018-12-12T00:
source share

An example of creating an array from an HTMLCollection

 <ul id="myList"> <li>0</li> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> <script> var tagList = []; var ulList = document.getElementById("myList"); var tags = ulList.getElementsByTagName("li"); //Dump elements into Array while( tagList.length != tags.length){ tagList.push(tags[tagList.length]) }; tagList.forEach(function(item){ item.addEventListener("click", function (event){ console.log(tagList.indexOf( event.target || event.srcElement)); }); }); </script> 
+2
Sep 29 '15 at 17:07
source share

In the modern native approach, you can use "Array.from ()" - for example:

 const el = document.getElementById('get-this-index') const index = Array.from(document.querySelectorAll('li')).indexOf(el) document.querySelector('h2').textContent = 'index = ${index}' 
 <ul> <li>zero <li>one <li id='get-this-index'>two <li>three </ul> <h2></h2> 

''

+2
Apr 02 '18 at 23:47 on
source share

You can iterate through <li> to <ul> and stop when you find the correct one.

 function getIndex(li) { var lis = li.parentNode.getElementsByTagName('li'); for (var i = 0, len = lis.length; i < len; i++) { if (li === lis[i]) { return i; } } } 

Demo

+1
Aug 01 2018-12-12T00:
source share

If you want to write this compact all you need:

 var i = 0; for (;yourElement.parentNode[i]!==yourElement;i++){} indexOfYourElement = i; 

We simply iterate over the elements in the parent node, stopping when we find your element.

You can also easily do:

 for (;yourElement.parentNode.getElementsByTagName("li")[i]!==yourElement;i++){} 

if that's all you want to browse.

+1
Oct 04 '16 at 20:37
source share

Another example: just use the base loop and index check

HTML

 <ul id="foo"> <li>0</li> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> 

JavaScript starts onload / ready or after ul is displayed.

 var list = document.getElementById("foo"), items = list.getElementsByTagName("li"); list.onclick = function(e) { var evt = e || window.event, src = evt.target || evt.srcElement; var myIndex = findIndex(src); alert(myIndex); }; function findIndex( elem ) { var i, len = items.length; for(i=0; i<len; i++) { if (items[i]===elem) { return i; } } return -1; } 

Execution example

jsFiddle

0
Aug 01 2018-12-18T00:
source share

Just pass the object reference to the next function and you will get an index

 function thisindex(elm) { var the_li = elm; var the_ul = elm.parentNode; var li_list = the_ul.childNodes; var count = 0; // Tracks the index of LI nodes // Step through all the child nodes of the UL for( var i = 0; i < li_list.length; i++ ) { var node = li_list.item(i); if( node ) { // Check to see if the node is a LI if( node.nodeName == "LI" ) { // Increment the count of LI nodes count++; // Check to see if this node is the one passed in if( the_li == node ) { // If so, alert the current count alert(count-1); } } } } } 
0
Aug 01 2018-12-18T00:
source share
  const nodes = Array.prototype.slice.call( el.parentNode.childNodes ); const index = nodes.indexOf(el); console.log('index = ', index); 
0
May 13, '19 at 8:52
source share



All Articles