Rafael Camargo

Using CSS :has to style a parent element when a child element is focused

For a while now, the internet has been flooded with articles about the :has pseudo-class. Most of them, though, come with terrible examples — like the ones in the MDN documentation. These examples are so disconnected from the day-to-day needs of developers that they discourage people from adopting :has, downgrading it to some kind of secondary resource.

Unlike lots of weird examples you see all over the web, the one explored in this post is an everyday use case. It's based on a list of elements containing links as children.

Check out what happens when you navigate through the links in this list using the Tab key:

Links getting highlighted with the browser's default outline

If we wanted to highlight the entire list item when its link gets focus — giving it a card-like appearance instead of just the link's default outline — we would've needed JavaScript not too long ago. We'd have had to: (a) remove the link's default outline style, (b) set up event listeners for focus and blur on the link element, and then (c) add a CSS class to the link's parent on focus, removing it on blur. A sweaty, tedious job.

Another option would've been wrapping the entire list item content with the link, instead of limiting it to just the post heading. Sure, this saves you the JavaScript headache, but it introduces CSS annoyances, like the link's default styles (e.g., underlining) being applied to other elements, such as the excerpt and date, which would then require extra tweaking. Plus, clicking anywhere on the list item would trigger navigation to the post, which might not be the experience you're looking for.

With global support now over 93%, the :has pseudo-class has made this an easy-peasy task. All it takes is a few lines of CSS:

li {
  padding: 20px;
  box-shadow: 0 0 0 0 #29303D;
  border-radius: 12px;
  box-sizing: border-box;
  transition: all 300ms ease-out;
}

li a {
  outline: 0;
}

li:has(h2 > a:focus) {
  box-shadow: 0 0 0 6px #29303D;
}

That last selector clearly expresses the following condition: when a link inside an h2 gets focus, apply the specified styles to the parent list item li.

Highlighting the list item when its link gets focus

Hands-on: On this Gist, you'll find a single HTML file with all the necessary code to run the example locally.

Learn more: If you liked this post, you might also enjoy learning how to use CSS flexbox to make an element fill all the remaining space.