The has() Selector Explained

The Gap :has() Fills

CSS has always been able to select a child based on its parent, but never the reverse - there was no way to style a parent based on what it contains. :has() is often described as the long-awaited "parent selector."

Basic Usage

.card:has(img) {
  padding: 0; /* cards with an image get no padding */
}

This styles a .card element differently depending on whether it happens to contain an <img> - something that was impossible in CSS before :has().

Styling a Container Based on an Input's State

.form-group:has(input:invalid) {
  border-left: 3px solid red;
}
.form-group:has(input:focus) {
  background: #f0f7ff;
}

This lets a wrapping element react to the validation or focus state of an input inside it, without needing any JavaScript to add or remove a class manually.

Combining with Sibling Selectors

h2:has(+ p) {
  margin-bottom: 0.5em; /* only if a paragraph immediately follows */
}

Common Practical Uses

  • Styling a form field's wrapper based on validation state.
  • Adjusting a card's layout depending on whether it contains an image, video, or just text.
  • Highlighting a table row that contains a specific status cell.

A Note on Performance

:has() is powerful, but checking a subtree for a condition is inherently more work for the browser than a simple selector. It performs well for typical use cases, but is not a reason to avoid state classes entirely in performance-critical, deeply nested structures.

Written by Lorens Mishra

Software Engineer Notes Management System Administrator

Continue reading

All CSS notes →

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.