Search code examples
javascriptcsshtml-listsselectors-api

querySelectorAll not working with nested ULs


I am seeing something weird with querySelectorAll being called on nested UL objects. Can somebody confirm that this is a bug, or am I thinking about it wrong?

Given this html:

<ul class="first">
<li>
    <ul class="second">
        <li class="third"></li>
    </ul>
</li>

I am finding that using the selector 'ul.second li' with querySelectorAll returns li.third even when called like so:

var ulSecond = document.querySelectorAll('ul')[1];
ulSecond.querySelectorAll('ul.second li'). // result is li.third

Am I crazy? I've tried a bunch of other cases and they all work correctly but this doesn't.

Here's a fiddle of what I'm trying to do.

https://jsfiddle.net/gh9j04v5/


Solution

  • I think your confusion is that calling querySelectorAll('ul.second li') on the <ul class="second"> is returning you <li class="third"></li> when you expect it to be empty.

    When you execute querySelectorAll it searches the element's descendants for elements that match the query, as the entire query.

    So for your example, it finds any descendant of "second" that "is an LI element with ul.second as an ancestor".

    It doesn't sequentially find each element in the query like

    elem.querySelectorAll('ul.second')...forEach(querySelectorAll('li'))
    

    or "find all ul.second under elem and then find each li under those"

    You can see this behavior on any page by using a query like

    document.body.querySelectorAll('body div')
    

    which will return all the divs in a page despite the query being issued on body