DEV Community 👩‍💻👨‍💻

Edwin
Edwin

Posted on

Practical CSS :has() selector examples

This article showcases how the CSS :has() selector can be used in everyday use cases.

For more examples, click the menu button or open the Codesandbox fullscreen. The source code is here.

Browser support

Currently, the :has() selector is only locked behind a feature flag in Firefox. It is available in all other modern browsers.

CSS :has browser support

Basics

In short, the :has() selector allows you to select a "parent" element based on a specific condition that you specify within the parentheses.

/** Select form that has a label */
form:has(label) {
   border: 1px solid #000;
}

/** x:has(a,b,c) --> x has (a OR b OR c) */
form:has(input[type="text"], input[type="checkbox"], input[type="number"]) {
   border: 1px solid #000;
}

/** x:has(a):has(b):has(c) --> x has (a AND b AND c) */
form:has(input[type="text"]):has(input[type="checkbox"]):has(input[type="number"]) {
   border: 1px solid #000;
}
Enter fullscreen mode Exit fullscreen mode

This is interesting, because it allows us to select the <form> and apply styles to it based on a condition. From there, we can also select elements further down the chain again!

/** select input within a form that has a label */
form:has(label) input {
   border: 1px solid red;
}
Enter fullscreen mode Exit fullscreen mode

This pattern opens up new ways of conditionally styling elements that were not possible before (without JS, hacks or workarounds). Things like:

  • Layout elements based on the contents of a container element.
  • Style a container based on the number of items inside it.
  • Applying styles to a container based on pseudo-classes (:hover, :disabled, :invalid) of a descendant.
  • Select the "previous sibling" element using :has(+ .other). Before, we could only select the "next sibling" element using the + operator.

Thoughts

  • CSS :has almost requires you to reset the way you think about selecting elements, as we could only write selectors that go further down the element tree, but now we can select elements back up as well.
  • Sometimes we need JavaScript to add classes to elements based on the state or data in our application. See the "Todo list" example, where we show a message when all checkboxes are ticked. The common way to achieve this is to iterate over the to-do item data, check if all items are 'completed' and conditionally render a message (or add a class) based on that data. But with :has(), we can apply styles to some element based on the UI state of a completely different element. For simple cases, you may no longer need JS at all!
  • When styling an element based on its contents, we need to think about separation of concerns. Adding some spacing to a <figure> element if it has an <img> or <figcaption> totally makes sense, but where do we draw the line? This applies to every type of CSS selector, I suppose, but with :has() you may be more easily tempted to write your CSS like a giant if-statement with a million cases.

What more?

Can you think of an awesome use case for :has()? let us know! 👇👇👇

to infinity and beyond

Top comments (0)

We are hiring! Do you want to be our Senior Platform Engineer? We're hiring for a Senior Platform Engineer and would love for you to apply.

Head here to learn more about who we're looking for.