DEV Community

Ayush Kumar
Ayush Kumar

Posted on

CSS :has() Is the Parent Selector We Waited 20 Years For

For years, the answer to "can CSS select a parent based on its children?" was a sad "no, use JavaScript."

Not anymore. :has() is supported in all modern browsers, and it changes how you write CSS. Here are three tricks you can use today.

1. Style a card differently if it contains an image

.card {
  display: grid;
  gap: 1rem;
}

.card:has(img) {
  grid-template-columns: 200px 1fr;
}
Enter fullscreen mode Exit fullscreen mode

No extra classes like .card--with-image. The CSS looks at the content and adapts.

2. Highlight a label when its input is invalid

label:has(+ input:invalid) {
  color: crimson;
}
Enter fullscreen mode Exit fullscreen mode

The label turns red when the input right after it fails validation. No JS, no state.

3. A dark mode toggle with zero JavaScript

<input type="checkbox" id="theme" />
<label for="theme">Dark mode</label>
Enter fullscreen mode Exit fullscreen mode
:root {
  --bg: #fff;
  --fg: #111;
}

:root:has(#theme:checked) {
  --bg: #111;
  --fg: #eee;
}

body {
  background: var(--bg);
  color: var(--fg);
}
Enter fullscreen mode Exit fullscreen mode

The checkbox lives anywhere in the page, and :root reacts to it.

Bonus: it works like a "not" too

/* Dim all siblings when one is hovered */
ul:has(li:hover) li:not(:hover) {
  opacity: 0.5;
}
Enter fullscreen mode Exit fullscreen mode

Wrap up

:has() lets CSS respond to the content and state of your markup, and that cuts a lot of "toggle a class" JavaScript.

What's the coolest thing you've built with it? Let me know in the comments

Top comments (0)