The has() selector
This is the first in an ongoing series of posts called CSS Painkillers, covering seldom heard or used CSS concepts easing my development journey. So, if it’s your cup of tea, follow for more!
For the longest time, and especially after the advent of JS frameworks (yes React is a framework too), it has been easier to apply dynamic styles via JS. Dynamic styles are pivotal to modern web applications since they are the backbone of interactivity. They allow for immediate user feedback after events. Therefore, using application state to conditionally and dynamically apply CSS styles is a common practice that most frameworks facilitate. Let’s take the following example:
There is a table in which the first cell in each row contains a checkbox to select or deselect the row. If the checkbox is checked, you apply a style (let’s say a background color) to the entire row to highlight it. Since using CSS selectors exclusively would be a painful approach, you would use JS. In Vue, you would do something like this:
<tr
v-for="row in someData"
:key="row.id"
:class="{ 'row-selected': row.isSelected } //dynamically adding a class here based on whether row is selected"
>
<td>
<input
:id="`row-${row.id}`"
type="checkbox"
:name="row.data"
:value="row.isSelected"
@change="toggleRowSelection"
/>
</td>
<!-- Rest of the cells -->
</tr>
Straightforward and easy to replicate across all frameworks. Until recently, I thought this was only way to accomplish this. I mean who would want to write CSS which looks like this?
/* Original background */
tr {
background-color: white;
}
/* Change background color when checked, targeting siblings of the input checkbox */
input:checked + td + td + td,
input:checked + td + td,
input:checked + td,
input:checked {
background-color: yellow;
}
Shivers. Anyway, things changed around 2022 when the eagerly waited has()
selector gained major(but not complete) browser support. All Chromium based browsers support it, Firefox is yet to implement it and support on mobile browsers is so-so. For the current state of browser support, check this.
The has()
selector, according to MDN, presents a way of selecting a parent element or a previous sibling element with respect to a reference element by taking a relative selector list as an argument. That’s …. surprisingly trivial, but hey, when you haven’t had something for the longest time (still waiting on Subgrid T_T), it’s a breath of fresh air.
Let’s see how the CSS using has()
looks like:
tr:has(input:checked) {
background-color: yellow;
}
And that’s it! A bit anti-climactic if you ask me. But this little guy is deviously powerful.
I just wanted to introduce the topic to you, hence kept the post short with a simple example. But the scope for using the selector is big. Study it well, and the world’s your oyster. And as always, remember it’s a Swiss Army knife, not a golden hammer.
So how do you see yourself using the has()
selector? Let me know in the comments!
Subscribe to my newsletter
Read articles from Abhishek S directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Abhishek S
Abhishek S
Lead UI Engineer at ThinkLink Inc. Product development is a craft and I'm hoping to become the best artisan.