The :has() CSS pseudo-class

I finally got a chance to work with the :has() CSS pseudo-class as part of Kelp, my UI library for people who love HTML.
Today, I wanted to quickly look at what it is and how it works. Let’s dig in!
If an element has a child or sibling, style the element CSS has long had all sorts of interesting selectors for targeting attributes that start or end with certain letters (^= and $=, respectively), or that have a certain parent/child (.


This content originally appeared on Go Make Things and was authored by Go Make Things

I finally got a chance to work with the :has() CSS pseudo-class as part of Kelp, my UI library for people who love HTML.

Today, I wanted to quickly look at what it is and how it works. Let’s dig in!

If an element has a child or sibling, style the element

CSS has long had all sorts of interesting selectors for targeting attributes that start or end with certain letters (^= and $=, respectively), or that have a certain parent/child (.parent > .child) or sibling (.sibling + .sibling) relationship.

But those selectors always target the last item in the selector chain.

For example, this applies styles to the .merlin class, if it’s a direct descendant of .wizard.

.wizard > .merlin {
	/* ... */
}

But what if you wanted to apply styles to .wizard if it contained .merlin as a direct descendant? The :has() pseudo-selector let’s you do that!

Here, we’re using :has() to style .wizard instead of .merlin.

.wizard:has(> .merlin) {
	/* ... */
}

This says that if an element with the .wizard class :has() a direct descendant with the .merlin class, add these styles.

As an aside, this is why I love CSS. You write it basically the way you’d speak it.

Siblings

Another cool use of :has() is styling elements with siblings.

You may be familiar with a pattern like this…

.wizard + .wizard {
	border-block-end: 1px solid #e5e5e5;
}

Let’s say you wanted borders between items but not after the last one.

This approach styles the sibling, not the item before it. So you either need to get weird with your CSS, or add a border before your elements instead of after.

.wizard + .wizard {
	border-block-start: 1px solid #e5e5e5;
}

But with :has(), can you target any item that has a sibling, rather than the sibling itself.

.wizard:has(+ .wizard) {
	border-block-end: 1px solid #e5e5e5;
}

How I’m using :has()

In Kelp, I use :has() to add borders between details elements when they’re combined into a disclosure group.

I also use to target a label if it has an input with the [trigger] attribute on it.

<label>
	<input type="checkbox" trigger>
	Show Password
</label>
label:has([trigger]) {
	/* Style the label */
}

Modern CSS rocks!

Like this? A Lean Web Club membership is the best way to support my work and help me create more free content.


This content originally appeared on Go Make Things and was authored by Go Make Things


Print Share Comment Cite Upload Translate Updates
APA

Go Make Things | Sciencx (2025-07-22T14:30:00+00:00) The :has() CSS pseudo-class. Retrieved from https://www.scien.cx/2025/07/22/the-has-css-pseudo-class/

MLA
" » The :has() CSS pseudo-class." Go Make Things | Sciencx - Tuesday July 22, 2025, https://www.scien.cx/2025/07/22/the-has-css-pseudo-class/
HARVARD
Go Make Things | Sciencx Tuesday July 22, 2025 » The :has() CSS pseudo-class., viewed ,<https://www.scien.cx/2025/07/22/the-has-css-pseudo-class/>
VANCOUVER
Go Make Things | Sciencx - » The :has() CSS pseudo-class. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/07/22/the-has-css-pseudo-class/
CHICAGO
" » The :has() CSS pseudo-class." Go Make Things | Sciencx - Accessed . https://www.scien.cx/2025/07/22/the-has-css-pseudo-class/
IEEE
" » The :has() CSS pseudo-class." Go Make Things | Sciencx [Online]. Available: https://www.scien.cx/2025/07/22/the-has-css-pseudo-class/. [Accessed: ]
rf:citation
» The :has() CSS pseudo-class | Go Make Things | Sciencx | https://www.scien.cx/2025/07/22/the-has-css-pseudo-class/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.