TaskBuild a card system where 'featured' status is detected via :has. .card { padding: 16px; border: 1px solid #e5e7eb; border-radius: 8px; }. .card:has(.featured-badge) { border-color: #F59E0B; box-shadow: 0 0 0 3px rgba(245,158,11,0.1); }. Two cards, one with <span class='featured-badge'>★</span>.
:has() — the parent selector finally arrives
100 XP7 min
Theory
The selector the web waited 20 years for
.card:has(img) { padding-top: 0; } /* cards that CONTAIN an image */
.card:has(.featured) { border: 2px solid gold; } /* cards with a .featured child */
form:has(input:invalid) { border-color: red; } /* form with any invalid input */:has(selector) matches the OUTER element if the inner selector matches anywhere inside. Finally — a parent selector in CSS.
The killer use cases
Style parents based on children
li:has(> input[type="checkbox"]:checked) {
text-decoration: line-through;
opacity: 0.6;
}Strikethrough a todo list item when its checkbox is checked. Pure CSS, no JS.
Layout shifts based on content
.layout:has(aside) { grid-template-columns: 1fr 240px; }
.layout:not(:has(aside)) { grid-template-columns: 1fr; }Layout shifts based on whether a sidebar exists.
Form validation styling
form:has(:invalid) button[type="submit"] {
background: #ccc;
cursor: not-allowed;
}Submit button disables visually when ANY input in the form is invalid.
Browser support
Shipped 2022-2023 in all evergreens. Safe in 2026.
Performance
:has does extra work — browsers optimize aggressively but avoid in HOT loops (every scroll frame). For static layout selectors, fine.
🔒
Sign up to start coding
Theory is open to everyone. The interactive editor, live preview, and check are unlocked with a 7-day free trial — card required, cancel anytime.
Sign up — free trial →First 10 lessons in each track are free. No card needed for those.