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 available in all modern browsers! ๐๐๐
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;
}
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;
}
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 giantif
-statement with a million cases.
What more?
Can you think of an awesome use case for :has()
? let us know! ๐๐๐
Top comments (0)