Parents counting children in CSS

posted on

The other day I was driving home when suddenly it hit me: We can use :has() to determine how many children a parent element has.

You might be thinking that Heydon Pickering already solved that 7 years ago in Quantity Queries for CSS, but that's not what I'm talking about.

/*  Quantity Queries for CSS by Heydon Pickering */
/* Three or more items */
li:nth-last-child(n+3) ~ li {
  background: red;

What I mean is that now we can style the parent element and other children differently depending on the number of items present anywhere in the parent element.

Note: :has() is only available in Safari 15.4+, Chrome 105+ or behind a flag in Firefox.

The following code checks if there are at least 3 list items in the list and adds a border to the parent if that's the case.

ul:has(li:nth-child(3)) {
  border: 1px solid red;

(↑ no border)

(↑ red border)

(↑ red border)

We can adapt the selector a bit and only apply the styling if there are exactly three list items.

ul:has(li:nth-child(3):last-child) {
  border: 1px solid blue;

(↑ blue border)

(↑ no border)

A demo

I’ve built a demo to illustrate what can be done. If you click on the element, start typing and press Enter, the parent element tells you how many items you should add.

Pretty awesome, right? Try it on CodePen.

Use cases

I can image that this can be useful in content builders in CMS. You can use CSS to give users visual feedback depending on the number of items they have added to a block or component.

Disclaimer: This is not tested and not production-ready. Only use this technique for progressive enhancement and only with proper testing. You shouldn’t use it to communicate important information, because changes may only be reflected visually and not semantically.

Safari and Chrome are the only browsers that support :has() at the moment. No, it won't stay like that. Other browsers will follow soon.

This solution might break, it's just a fun experiment. Don't use it in production.

I've extended this disclaimer and I've added a pink, dotted border because some people missed it before.