:has() — The Parent Selector

Style an element based on what it contains or what follows it — the selector we waited 20 years for.

For two decades the answer to “can CSS select a parent?” was a flat no. :has() finally changed that, and it's now supported in every modern browser. It matches an element if it contains something — or is related to something — that matches the inner selector.

Read it as “which has”

/* A card that contains an image looks different */
.card:has(img) { padding-top: 0; }

/* A label whose checkbox is checked */
label:has(input:checked) { font-weight: 700; }

/* A form group that contains an invalid field */
.field:has(:invalid) { border-color: crimson; }

Because it combines with the other combinators, you get things that used to require JavaScript. Want a figure to react when its caption is present? figure:has(figcaption). Want to style a whole row when any checkbox in it is checked? Done, no listeners.

The quantity query trick

Combine :has() with :nth-child to react to how many children exist — a genuinely new capability.

Example

Try it yourself
Loading editor…
Press Run to see the result.

When to use it

  • A developer uses :has(img) on a card to add extra padding only when the card contains an image, without a separate modifier class.
  • A designer uses form:has(input:invalid) to highlight the entire form container red when any input fails validation.
  • A developer uses .nav:has(.nav-link.active) to style the nav wrapper itself differently when any child link is the active page.

More examples

:has() for card with image variant

Uses :has(img) to remove top padding on cards that start with an image, letting the image flush to the card's rounded corners.

Example · css
.card { padding: 24px; }

/* Extra top padding only when card has an img child */
.card:has(img) {
  padding-top: 0;
}

.card img {
  width: 100%;
  border-radius: 8px 8px 0 0;
}

Form highlight on any invalid input

Highlights the form border and disables the submit button any time a child input fails browser validation.

Example · css
form:has(input:invalid) {
  border-color: #c0392b;
}
form:has(input:invalid) .submit-btn {
  opacity: 0.5;
  pointer-events: none;
}

:has() as next-sibling selector

Styles both the label and border of a field group when the contained input is focused — the first CSS parent selector.

Example · css
/* Style a label when its following input is focused */
.field:has(input:focus) label {
  color: #2965f1;
  font-weight: 600;
}

.field:has(input:focus) input {
  border-color: #2965f1;
  outline: none;
}

Discussion

  • Be the first to comment on this lesson.
:has() — The Parent Selector — CSS | SoundsCode