CSS `:has()` Isn’t New, But Most Developers Still Aren’t Using It Well

Make this shorter: CSS `:has()` Isn’t New, But Most Developers Still Aren’t Using It Well
January 14, 2026 | Read time: 4 minutes

The first native AI agent for mobile is here.

Droidrun is the first native mobile AI agent that lets LLMs control iOS and Android devices. The framework is the most powerful option available for mobile agents. It is also fully open source.

Check and contribute to the Droidrun repo

Sponsor this newsletter to reach 9,000+ active developers

The :has() selector is not a new CSS feature.

It has been supported long enough to be used in real projects.

Yet many developers still either avoid it or misunderstand what it is actually good for.

Let’s clear that up.

What :has() Really Does

:has() is a relational pseudo-class.

It allows CSS to select an element based on what it contains or what comes after it.

In simple terms, it lets CSS answer this question:

Style this element if that exists.

The Core Idea

                            
.card:has(img) {
  padding: 2rem;
}                            
                        

Only cards that contain an image get extra spacing.

No utility classes
No JavaScript
No extra markup

Where :has() Actually Shines

1) Form State Styling

                            
form:has(input:invalid) {
  border: 2px solid red;
}                            
                        

The form reacts to validation state automatically.

2) Checkbox Driven UI

                            
label:has(input:checked) {
  font-weight: bold;
}                            
                        

The label updates when the checkbox is checked.

3) Content Aware Layouts

                            
.article:has(h2) {
  grid-template-columns: 2fr 1fr;
}                            
                        

The layout adapts based on the content inside it.

4) Navigation State Styling

                            
nav:has(a.active) {
  background: black;
}                            
                        

The navigation reacts to the active link without JavaScript.

Why This Matters

Before :has():

  • Parents could not react to children
  • JavaScript was required for simple UI state
  • Markup had to carry extra classes

With :has():

  • CSS reacts to DOM state
  • HTML stays clean
  • Less JavaScript is needed

Things to Be Careful With

  • Avoid using :has() on very broad selectors
  • Do not attach it to * or body
  • Use it for localized, intentional conditions

Used well, it is safe and predictable.

Final Takeaway

:has() does not replace JavaScript.

It replaces unnecessary JavaScript.

If you already support modern browsers, it deserves a place in your CSS toolkit.