What I learned about nth-child selectors

Thursday, Mar 6, 2014 2 minute read Tags: css
Hey, thanks for the interest in this post, but just letting you know that it is over 3 years old, so the content in here may not be accurate.

Today I learned an interesting fact about how the nth-child CSS selector works and it was different to what I expected and what seems to make sense.

I had the following HTML snippet:

<div class="input-group">
    <div class="legacy">
        <div class="input-subgroup">
            <input name="itemId" id="Type0" type="radio" checked="checked" value="1">
            <label for="Type0">Single</label>
        </div>
        <div class="input-subgroup">
            <input name="itemId" id="Type1" type="radio" value="2">
            <label for="Type1">Couple</label>
        </div>
        <div class="input-subgroup">
            <input name="itemId" id="Type2" type="radio" value="3">
            <label for="Type2">Family</label>
        </div>
    </div>
    <div class="new">
        <div class="input-subgroup">
            <input name="somethingElse" id="somethingElse" type="text" maxlength="2" placeholder="Enter" value="">
        </div>
        <div class="input-subgroup">
            <input name="somethingElse2" id="somethingElse2" type="text" maxlength="2" placeholder="Enter" value="">
        </div>
    </div>           
</div>

And I wanted to find the input[type="radio"] at a particular position in the DOM.

So I started with this snippet:

var group = document.getElementsByClassName('input-group')[0];
var couple = group.querySelectorAll('.legacy input[type="radio"]:nth-child(2)');

And was confused when that didn’t work, I’m wanting to find the 2nd radio button, and that reads right, it’s the 2nd radio button under the class="legacy" element, so it makes sense… Right?

But I was missing a point, that it’s the nth-child and in my DOM input[type="radio"] isn’t actually a child of class="legacy", it’s a descendant so what I’m really after is nth-descendant, which isn’t a real selector.

The fix

It’s a pretty easy fix if you know your DOM, change the selector to:

.legacy :nth-child(2) input[type="radio"]

Since we know that the radio button is in the nth-child(2) of .legacy and we are properly locating the children based on their position.

You can see the broken one here and the working one here.