Codectionary / Developer documentation / CSS

:has() - The Parent Selector

:has() matches an element if any of the selectors passed to it match something within it - effectively letting you style a parent based on its children or descendants, something CSS could never do natively before. It has broad, mainstream browser support as of 2026 and is safe to use in production.

Syntax

:has(selector)

Examples

Styling a Parent Based on Its Children

Highlighting a form group only if it contains an invalid input.

/* Demo setup: sizing, structure or neutral surfaces. */
.form-group{padding:1rem}input{display:block;margin-block:.5rem;padding:.5rem}

.form-group:has(input:invalid) {
  border-left: 3px solid red;
  background: #fef2f2;
}
  1. The invalid email input makes its form-group parent match :has(input:invalid).
  2. Enter a valid address such as john@example.com to remove the invalid-parent styling.
  3. CSS reflects validity; this standalone preview does not submit or register anything.
HTML used by this example
<div class="form-group"><label for="email">Email address</label><input id="email" type="email" value="not-an-email" required></div>

Conditional Layout Based on Content

Changing a card's layout depending on whether it contains an image.

/* Demo setup: sizing, structure or neutral surfaces. */
.card{display:grid;gap:1rem;border:1px solid #94a3b8;padding:1rem;margin-block:1rem}.preview-photo{width:100px}

.card:has(img) {
  grid-template-columns: 100px 1fr; /* image + text layout */
}

.card:not(:has(img)) {
  grid-template-columns: 1fr; /* text-only layout */
}
  1. Both articles use the same base grid display.
  2. The presence of an image selects the two-column variant.
  3. The article without an image uses one column; :has does not create the parent’s grid formatting context by itself.
HTML used by this example
<article class="card"><img class="preview-photo" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22480%22%20height%3D%22240%22%20viewBox%3D%220%200%20480%20240%22%3E%3Crect%20width%3D%22480%22%20height%3D%22240%22%20fill%3D%22%23e0f2fe%22%2F%3E%3Ccircle%20cx%3D%22365%22%20cy%3D%2255%22%20r%3D%2230%22%20fill%3D%22%23fbbf24%22%2F%3E%3Cpath%20d%3D%22M0%20240%20135%2055%20280%20240%22%20fill%3D%22%230f766e%22%2F%3E%3Cpath%20d%3D%22m150%20240%20155-150%20175%20150%22%20fill%3D%22%235b21b6%22%2F%3E%3Ctext%20x%3D%2220%22%20y%3D%22218%22%20fill%3D%22white%22%20font-size%3D%2224%22%20font-family%3D%22sans-serif%22%3EOriginal%20landscape%3C%2Ftext%3E%3C%2Fsvg%3E" alt="A sun above green and purple mountains"><p>A lesson with an illustration.</p></article><article class="card"><p>A text-only lesson.</p></article>

Sibling-Based Styling

A powerful combination: styling an element based on the state of a sibling.

/* Demo setup: sizing, structure or neutral surfaces. */
.field input{border:2px solid #64748b;padding:.5rem}

.field:has(+ .error-message) input {
  border-color: red; /* highlights an input if an error message follows it */
}
  1. The error message is the field wrapper’s adjacent sibling.
  2. :has(+ .error-message) therefore identifies the preceding field wrapper.
  3. The nested input receives the error border; a real validation flow must also connect messages accessibly.
HTML used by this example
<div class="field"><label for="topic">Topic</label><input id="topic" value=""></div><p class="error-message">Choose a topic.</p>

Parameters and values

  • :has(selector) (pseudo-class): Matches if the given selector matches anything inside the element

Best practices

  • Use :has() to replace many patterns that previously required JavaScript, like styling a form field based on its own validity state
  • Combine :has() with :not() to style elements that specifically lack certain children
  • Keep :has() selectors reasonably simple - deeply nested conditions can become hard to reason about, even though they are valid
  • Use :has() for genuinely conditional styling based on content structure, not as a general replacement for simple class-based styling

Browser compatibility

chrome
Yes
firefox
Yes
safari
Yes
edge
Yes

These are the existing reference’s support labels, not tested minimum versions. Individual values and APIs can have different support. Check the linked specification before choosing a browser target.

CSS specifications (modules)

Specifications & further reading