Playground, :has() real patterns, and hidden gems that replace JavaScript.
Each selector highlights the exact elements it matches in a live HTML tree. These are the selectors most developers know exist but never actually use.
:has() is the CSS parent selector. These are the real-world patterns you've been writing JavaScript for — now done in pure CSS. Interact with each demo.
The left card has an image — CSS detects this with :has(img) and applies a teal border and bolder text. No JavaScript class toggling needed.
Click an input — the label turns cyan. The parent .demo-form-group detects its child's focus via :has(input:focus) and changes the label color.
Checked rows turn green automatically. The label detects its own checkbox state via :has(input:checked) — replacing a JavaScript event listener.
Nav items that have a .dropdown child automatically get a ▾ arrow via :has(.dropdown)::after. No JavaScript class detection needed.
When the list has no children, :empty::after inserts the "No items" message. Add items to see it disappear. Pure CSS state — zero JavaScript for the UI.
Add a 3rd item — the grid switches to 3-column automatically via :has(:nth-child(3)). Layout changes based on content count with zero JavaScript.
These selectors exist in all modern browsers. Most developers have never used them. Interact with each demo.
Style a parent when any of its children has focus — no JavaScript needed for form group highlighting.
True when the placeholder is visible — i.e., the field is empty. Powers floating labels with zero JavaScript.
Like :valid/:invalid but only activates after the user interacts. Avoids showing red errors on an untouched empty form.
Count only elements matching a selector. :nth-child(2 of .featured) selects the 2nd featured item — not the 2nd child that happens to be featured.
Auto-decorate links by type — no extra classes or JavaScript:
Custom list bullets without images or list-style: none hacks. And use :is() to write DRY heading rules.