A Simple CSS Selector That Most Devs Never Try - the :has() Selector
If you ask a group of developers: “Hey, have you used :has() before?”
Most of them will look at you like: “Bro, is that even real CSS?”
Yes. It is real. It is powerful. And honestly… it feels a bit illegal because CSS is not supposed to be this smart. But here we are.
Today I want to share this “new old” CSS superpower that can change how you build UI logic — without JavaScript. And trust me, you will feel like a magician.
What Is :has()?
The official definition is something like:
“Select an element if it contains something that matches the selector inside.”
But in simple language::has() is the closest thing we have to a “parent selector” in CSS.
With :has(), you can style a parent based on what the child looks like.
Something like:
.card:has(img) {
border: 2px solid blue;
}
Boom.
If .card contains an <img>, it becomes blue.
CSS just checked the inside and reacted.
Why It Feels Like CSS With Superpowers
Before :has(), CSS always felt like working with strict Vietnamese parents:
-
You can look at your children (descendant selectors)
-
But you cannot look at your parents
-
No arguments, no exceptions :))
But now :has() says:
“Don’t worry bro, I can look up, I can look down, I can check neighbors— I handle everything.”
Here are some things you can suddenly do:
- Style a form when an input is invalid
No JS. No event listener. Just CSS.
form:has(input:invalid) {
border: 2px solid red;
}
Boom. Instant feedback UI.
2. Change button style when a checkbox is checked
Classic “Enable button when user agrees”.
button:has(+ input:checked) {
background: green;
}
3. Accordion without JavaScript
Yes, you read that right.
.item:has(.content.open) {
max-height: 200px;
}
A Real Example (Dev-Friendly)
Let’s say you want to highlight a .product-card only when it has .sale-tag.
.product-card:has(.sale-tag) {
background: #fff7e6;
border-color: orange;
}
Result:
When the sale tag appears → whole card becomes “on sale mode”.
And you didn’t write even one line of JavaScript.
Feels good right?
Browser Support?
Good news:
-
Chrome ✔
-
Safari ✔
-
Edge ✔
-
Firefox ✔
Why Most Devs Don’t Use It Yet
Because:
-
They don’t know
-
They think it’s not supported
-
They heard about it once but forgot
-
CSS scares them
-
That mindset of "Just use JavaScript, it’s faster."
But once you try :has(), you will realize it’s the missing piece we always wanted.
When Should You Use :has()?
Use it when you want CSS to react to the structure of the HTML.
Great for:
-
Forms
-
Cards
-
Interactions
-
Accordions
-
Navigation menus
-
Any “state” that depends on children
Not great for:
-
Complex app logic
-
Heavy UI state (JS vẫn làm tốt hơn)
Final Thought
The :has() selector is honestly a game changer.
It’s like the day you learned Flexbox or Grid for the first time — your brain expands a little bit.
With :has() you can:
-
Style based on children
-
Create UI states without JS
-
Make smarter components
-
Reduce code complexity
-
Make CSS fun again
So next time you code UI, give this selector a try.
Maybe you'll feel like a CSS wizard for 5 minutes.
Worth it.