The CSS :has() Selector Explained
How the CSS :has() selector lets you style a parent based on its children - the long-awaited parent selector - with practical, real-world patterns.
6 min read - Updated 2026-06-18
:has() is the parent selector CSS lacked for two decades. It matches an element based on what it contains, so you can finally style a container by its children, a label by its input's state, or a card by whether it holds an image - all without JavaScript.
How :has() works
Put a relative selector inside :has() and the element matches when it contains something matching that selector. The match target stays the outer element, not the child.
figure:has(figcaption) - figures that contain a caption
label:has(input:checked) - labels whose input is checked
div:has(> img) - divs with a direct image child
article:has(h2, h3) - articles containing a subheading
Patterns you could not do before
Because :has() reacts to descendant state, it unlocks layout and styling decisions that previously required scripting or extra wrapper classes.
Style a form row that contains an invalid field: .row:has(:invalid)
Add spacing only to cards that include media
Highlight a list item whose link is focused: li:has(a:focus)
Combine with :not() to target containers missing a child
Support and performance notes
:has() is supported in all current major browsers. It is well optimized, but very broad selectors evaluated on large trees are worth sanity-checking.
Baseline-supported in current Chrome, Edge, Safari, and Firefox
Provide a sensible default for very old engines via graceful degradation
Keep the relative selector specific rather than universal
Verify the effect live across breakpoints and states
Release checklist
Replace JS-driven parent classes with :has() where possible.
Keep the inner selector specific for clarity and performance.
Provide fallbacks for browsers without :has().
Test interactive states (:checked, :invalid, :focus) in context.
Frequently asked questions
What does the CSS :has() selector do?
:has() matches an element based on its descendants. It is effectively the parent selector - figure:has(figcaption) styles figures that contain a caption, something CSS could not do natively before :has().
Is :has() supported in all browsers?
Yes, :has() is supported across all current major browsers. For older engines, design a sensible default and treat the :has() styling as an enhancement.
Can :has() check for the absence of an element?
Combine it with :not() - for example article:not(:has(img)) targets articles that do not contain an image. This pairing covers most "only when missing" use cases.
Related guides
Benji
Your life OS
The companion app that keeps every area of your world in sync.
Zero to Shipped
Ship products, not side projects
The ultimate Next.js boilerplate for building and launching real products.
DMX
Mindful Twitter/X
The intentional X client for macOS. Reclaim your attention span.
Sotto
Voice-to-text for macOS
Speak naturally. Type instantly. 100% local & private.
Passlock
Password manager with willpower
Lock passwords with time delays, word challenges, or hand the keys to someone you trust.
Glink
Changelogs that slap
Beautiful changelogs and roadmaps for your product.
JoinRepo
GitHub access control
Monetize your GitHub repositories with ease.
Tubely
YouTube Studio for Mac
Manage multiple YouTube channels in one native app.
JustWrite
Distraction-free writing
A minimal writing app that helps you focus on what matters.