CSS :has() Selector: The Parent Selector We've Been Waiting For
Problem
Styling a parent element based on its child’s state used to require JavaScript.
checkbox.addEventListener('change', (e) => {
e.target.closest('.card').classList.toggle('selected');
});
Simple style toggling shouldn’t need JavaScript.
Solution
The :has() selector makes this possible with pure CSS. Supported in all modern browsers.
/* Card with a checked checkbox */
.card:has(input:checked) {
border-color: #3b82f6;
background-color: #eff6ff;
}
/* Post item that contains an image */
.post-item:has(img) {
grid-template-columns: 200px 1fr;
}
/* Form group with an empty input */
.form-group:has(input:placeholder-shown) {
opacity: 0.7;
}
More practical examples:
/* Red border when error message is visible */
.field:has(.error-message:not(:empty)) input {
border-color: #ef4444;
}
/* Remove padding for sections with video */
section:has(video) {
padding: 0;
}
Key Points
:has()lets you select parent or sibling elements conditionally in pure CSS- Replaces JavaScript for state-based styling in many common scenarios
- Supported in all modern browsers (Chrome 105+, Firefox 121+, Safari 15.4+)
- Avoid deeply chained
:has()selectors — they can impact rendering performance