Skip to main content
Ben Nadel at CFUNITED 2009 (Lansdowne, VA) with: Kim
Ben Nadel at CFUNITED 2009 (Lansdowne, VA) with: Kim

Using :scope To Identify The Host Element In .querySelectorAll()

By
Published in , Comments (4)

Here's a helpful tip that I learned the other day. When using a Document Object Model (DOM) method to query for HTML elements using a CSS selector (ex, .querySelectorAll()), the :scope pseudo-class can be used to identify the host element on which the method is being called. This allows us to use the direct descendant selector (>) to target children of the host element.

Run this demo in my JavaScript Demos project on GitHub.

View this code in my JavaScript Demos project on GitHub.

Consider this HTML snippet:

<p>
<span> <em>1</em> </span>
<span> <em>2</em> </span>
<span> <em>3</em> </span>
<span> <em>4</em> </span>
<span> <em>5</em> </span>
<span> <em>6</em> </span>
<span> <em>7</em> </span>
<span> <em>8</em> </span>
<span> <em>9</em> </span>
<span> <em>10</em> </span>
</p>
view raw snippet-1.htm hosted with ❤ by GitHub

If we wanted to query the p element for "odd children", how would we do it? My first instinct was to try and call:

.querySelectorAll( " > :nth-child(odd) " )

Unfortunately, this isn't a valid CSS selector since there's nothing anchoring the direct descendant (>) selector. So, we might try to anchor it to *:

.querySelectorAll( " * > :nth-child(odd) " )

This runs without error; but, it doesn't do what we want. In the above snippet, it ends up selecting every distant descendant <em> element since each of them is the first (odd) child within a <span>.

The solution is to use the :scope pseudo-class. This represents the element on which the .querySelectorAll() method is being called:

.querySelectorAll( " :scope > :nth-child(odd) " )

To see this in action, I've created a demo that uses this selector and applies a background-color to the targeted nodes:

<!doctype html>
<html lang="en">
<body>
<p onclick="selectOdds( event )">
<span> <em>1</em> </span>
<span> <em>2</em> </span>
<span> <em>3</em> </span>
<span> <em>4</em> </span>
<span> <em>5</em> </span>
<span> <em>6</em> </span>
<span> <em>7</em> </span>
<span> <em>8</em> </span>
<span> <em>9</em> </span>
<span> <em>10</em> </span>
</p>
<script type="text/javascript">
function selectOdds( event ) {
var targets = event
.currentTarget
// In the selector, ":scope" represents the current element on which the
// query is being called. This allows us to use the direct-descendant
// operator since it gives us a way to identify the parent of the direct
// descendants.
.querySelectorAll( ":scope > :nth-child( odd )" )
;
for ( var node of targets ) {
node.style = "background-color: hotpink ; color: white ;";
}
}
</script>
</body>
</html>
view raw index.htm hosted with ❤ by GitHub

If I click on the <p> tag and execute the onclick handler, we locate the odd direct-descendants and highlight them in hawt pink:

Screenshot showing that the odd children have been altered.

As you can see, each of the odd direct-descendants of the host element were highlighted in hot pink.

The :scope pseudo-class, which I hadn't heard of until a few days ago, has been widely supported for many years. The last browser to add support for it was Edge back in 2019.

Want to use code from this post? Check out the license.

Reader Comments

9 Comments

I've really enjoyed using querySelector and querySelectorAll. I got tired of typing out though so I typically create a function to handle the calls:

const qs = (obj, container = document)=> container.querySelector( obj )
const qsa = (obj, container = document)=> container.querySelectorAll( obj )

//My historical solution
qsa("span:nth-child( odd )", event.currentTarget).forEach((node)=> node.style.fontSize = "1.5rem")

//I like yours though
qsa(":scope > nth-child( odd )", event.currentTarget).forEach((node)=> node.style.fontSize = "1.5rem")

Always something to learn.

16,020 Comments

@Hugh,

I love the idea of the short-hand methods. This is one of my biggest sentimental misses from the jQuery days. It's just hard to ever feel like anything is easier / better than $() 😄 Even in HTMX - the framework that I'm learning right now - has it's own htmx.find() method internally, that does something very similar to what you've done as well.

Post A Comment — I'd Love To Hear From You!

Markdown formatting: Basic formatting is supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.
Cancel
I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel