CSS :has() Selector

The CSS :has() selector lets you style an element when it contains, follows, or relates to another matching element. It is often called a relational selector because it can select a parent based on what is inside it.

Before :has(), many parent-state styling problems needed JavaScript. Now you can solve several of them directly in CSS, such as highlighting a card that contains a checked checkbox or styling a heading when a paragraph follows it.

CSS :has() Syntax

Write :has() after the element you want to style. Inside the parentheses, add the selector that must match.

Syntax:

selector:has(condition) {
  property: value;
}
Selector Meaning
article:has(img) Selects an article that contains an image
label:has(input:checked) Selects a label with a checked input inside
h2:has(+ p) Selects an h2 immediately followed by a paragraph
form:has(:invalid) Selects a form that contains invalid fields

Style a Parent Element

The most common use of :has() is styling a parent when it contains a specific child element.

Example:

/* Style a card only when it contains an image. */
.card:has(img) {
  border-color: royalblue;
  background-color: #f2f6ff;
}

Style a Selected Item

You can combine :has() with form states such as :checked. This lets you style the whole row when a checkbox or radio button changes.

Example:

/* Highlight the label that contains a checked input. */
.option:has(input:checked) {
  color: seagreen;
  font-weight: bold;
}

Validate Forms with CSS

:has() can detect invalid fields inside a form or section. This helps you show a visual warning without writing a custom validation script.

Example:

/* Add a warning border when any field is invalid. */
.signup-form:has(:invalid) {
  border: 2px solid crimson;
}

Use Relative Selectors

The selector inside :has() can describe a relationship. For example, + p means an adjacent paragraph that comes immediately after the selected element.

Example:

/* Reduce spacing when a paragraph directly follows the heading. */
h2:has(+ p) {
  margin-bottom: 6px;
}

Runnable Browser Example

This example styles each list item when its checkbox is selected. The parent list item changes color without JavaScript.

Example:

<ul class="task-list">
  <li>
    <label>
      <input type="checkbox">
      <span>Review landing page copy</span>
    </label>
  </li>
</ul>

<style>
  /* Style the parent li when its checkbox is checked. */
  .task-list li:has(input:checked) {
    background: #ecfff2;
    border-color: seagreen;
  }
</style>

Specificity of :has()

The :has() selector takes the specificity of the most specific selector inside it. This behavior is similar to :is() and :not().

Example:

/* The #featured selector increases specificity. */
.card:has(#featured) {
  border-width: 3px;
}

Practical Guidelines

  • Use :has() when CSS can express the relationship clearly.
  • Keep selectors short because complex relational selectors can be harder to maintain.
  • Use it for parent styling, form state, and layout adjustments.
  • Check browser support if your audience includes older browsers.
  • Avoid using :has() as a replacement for business logic that belongs in JavaScript.

Tip: Start with simple parent-state selectors. They are easier to read and usually give the biggest improvement over JavaScript-only styling.

Conclusion

The CSS :has() selector makes parent-aware styling possible in CSS. Use it to highlight elements based on children, form states, and nearby elements while keeping your styles clear and maintainable.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram