The CSS :has() selector
The CSS :has() pseudo-class selects an element based on what it contains — .card:has(img) matches cards that contain an image. It is the long-requested "parent selector," letting you style an element from its descendants or even its later siblings, which previously required JavaScript.
Overview
:has() answers a question CSS could not ask for two decades: "does this element contain something matching X?" .card:has(img) selects the cards that have an image inside them, and styles the card — not the image. Because it lets a parent react to its children, it is universally known as the parent selector.
Its reach goes well beyond children. label:has(+ input:focus) styles a label when the input next to it is focused; form:has(:invalid) styles a whole form while any field inside is invalid; .gallery:has(:hover) can dim a gallery whenever any item is hovered. Combined with the sibling combinators, it can even react to what comes after an element — something no selector could do before.
This unlocks a huge amount of UI that used to need JavaScript: layouts that adapt to their content, forms that respond to their own validity, components that style themselves based on their parts. Browser support is now solid across the board, so it is ready for everyday use.
Syntax
/* a card that contains an image */
.card:has(img) { … }
/* a form with any invalid field */
form:has(:invalid) .submit {
opacity: 0.5;
}
Example
<style>
.card { border: 2px solid #e2e8f0; border-radius: 10px; padding: 14px; font: 15px system-ui, sans-serif; margin-bottom: 8px; }
.card:has(.badge) { border-color: #1c7ce9; background: #eff6ff; }
.badge { background: #1c7ce9; color: #fff; padding: 2px 8px; border-radius: 999px; font-size: 12px; font-weight: 700; }
</style>
<div class="card"><span class="badge">New</span> This card contains a badge, so :has() highlights it.</div>
<div class="card">This plain card is left alone.</div>
Best practices
- Use it to style an element from its contents — the parent selector pattern that once needed JavaScript.
- Combine it with sibling combinators (
:has(+ input:focus)) to react to neighboring elements. - Reach for
form:has(:invalid)and similar to drive UI from state without scripting. - Keep the inner selector reasonably simple for readability;
:has()can express a lot, so clarity matters.
Frequently asked questions
What is the CSS :has() selector?
.card:has(img) matches cards with an image. It is the long-awaited parent selector.Is there a parent selector in CSS?
:has(). .parent:has(.child) styles the parent when it contains a matching child, which was impossible before.Can :has() react to sibling elements?
h2:has(+ p) matches an <h2> that is immediately followed by a paragraph.