CSS :scope Pseudo Class
The :scope CSS pseudo-class represents scope elements. Read about the pseudo-class and practice with examples.
The CSS :scope pseudo-class matches the element that a selector is being resolved against — its reference element. In plain DOM queries that reference element is the element you call the query method on; inside a Shadow DOM it is the shadow root.
This page explains what "scope" means for a selector, why :scope is mostly a JavaScript tool rather than a stylesheet tool, the two main places it changes behavior, and the gotchas to watch for.
What the reference element is
Every selector is matched relative to some element. When you write CSS in a stylesheet, the reference element is the document root, so :scope there is equivalent to :root and is rarely useful on its own.
:scope becomes meaningful when the reference element is not the root — most importantly when you query the DOM from JavaScript:
element.querySelector(selector)andelement.querySelectorAll(selector)resolve the selector againstelement. Here:scoperefers toelementitself.- A
ShadowRoot's query methods use the shadow root as the reference element.
Without :scope, a selector passed to element.querySelector() is still matched against the whole subtree, not anchored to element. That surprises many developers — see the gotcha below.
Why use it
The main reason to reach for :scope is to anchor a selector to the element you are querying, so you can match direct children or otherwise express "relative to here":
// Match only sections that are direct children of container.
container.querySelectorAll(':scope > section');:scope is meaningful inside the query methods listed above (querySelector, querySelectorAll, and the live Element.matches() check). It has no special effect in closest() or in ordinary stylesheet rules.
Note: the old <style scoped> attribute, which once let a <style> block apply only inside its parent element, was removed from browsers. Style scoping today is done with Shadow DOM (or build-time tooling), and :scope survives as the DOM-query helper.
Version
Syntax
In a stylesheet the syntax is the same as any other pseudo-class:
:scope {
/* declarations — equivalent to :root in a normal stylesheet */
}In JavaScript it is passed inside the selector string:
element.querySelectorAll(':scope > .child');Example: anchoring a query to its element
In the example below, container.querySelector(':scope > section') selects only the <section> that is a direct child of .container. The matched section is recolored to confirm the query found it.
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
.container {
margin: 40px auto;
max-width: 700px;
background-color: #eeeeee;
padding: 20px;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.25);
}
section {
padding: 30px;
}
</style>
</head>
<body>
<h2>:scope selector example</h2>
<div class="container">
<section>
<p>
Inside the scope.
</p>
</section>
</div>
<script>
const container = document.querySelector('.container');
const scopeElement = container.querySelector(':scope > section');
scopeElement.style.backgroundColor = '#1c87c9';
scopeElement.style.color = '#fff';
</script>
</body>
</html>Common gotcha: selecting direct children
The most common reason to use :scope is selecting the immediate children of the element you are querying. A combinator like > .x cannot stand on its own — element.querySelector('> .x') throws a SyntaxError. You need a left-hand side, and :scope provides it:
<ul id="list">
<li>A</li>
<li>
<ul>
<li>B (nested)</li>
</ul>
</li>
</ul>const list = document.getElementById('list');
// SyntaxError — "> li" is not a complete selector:
// list.querySelectorAll('> li');
// Correct: only the direct <li> children of #list (A and the one wrapping the nested list),
// NOT "B (nested)".
list.querySelectorAll(':scope > li');Without :scope, list.querySelectorAll('li') would also return the nested B item, because a plain descendant selector reaches the whole subtree. :scope > is the idiomatic way to say "direct children of the element I'm querying."
Browser support
:scope is supported in all modern browsers for the DOM query methods. It has no effect as a styling rule in a normal stylesheet beyond behaving like :root.
Related chapters
- CSS Selectors — the full selector reference.
- CSS Selector — selector syntax basics.