CSS :focus-within
The :focus-within
pseudo-class is a CSS Level 4 selector that is supported by FireFox 52+, Safari 10.1+, iOS Safari 10.3+, Opera 47+ and Chrome 60+. When first writing this piece back in 2017, support for Chrome had just been announced behind a feature flag, but outside of Internet Explorer and Edge, there is little reason to at least play with this selector a bit.
So what does it do, and why is it awesome?
:focus-within
is a pseudo-class you add to an existing CSS selector, much like you would with :focus
or :hover
. The pseudo-class styling kicks in when either the element with :focus-within
becomes focused, or a focusable child of that element receives keyboard focus.
Let’s review the following demo and accompanying code. Try keyboard tabbing through the demo:
<div class="my-element">
<p>A paragraph</p>
<p>
<a href="https://scottohara.me">
My Website
</a>
</p>
<label for="wut_email">
Your email:
</label>
<input type="email" id="wut_email">
</div>
/*
A crude selector allowing any element
that can receive focus within the
.my-element parent to receive
a yellow background.
*/
.my-element *:focus {
background: yellow !important;
color: #000;
}
/*
The following :focus-within example
will NOT style the elements within
the .my-element selector, like the
normal :focus above, but will
style the .my-element container
when its focusable children
receive focus.
*/
.my-element:focus-within {
outline: 3px solid #333;
}
The above .my-element
will receive a 3px outline if it programatically receives focus (because <div>
s are not meant to receive keyboard focus, without a set tabindex
), or if the link or input elements within the <div>
receive focus. You can play around with the above basic focus-within demo on codepen.
Focus-within examples
:focus-within
is pretty powerful and is not a pseudo-class you would want to add to elements all willy-nilly. Since the pseudo-class activates when any element within it receives focus, it definitely should be used sparingly and likely not on an element that contains many sub-components that also contain focusable child elements.
With that said, there are some common UX interactions that would benefit from :focus-within
’s behavior, that were previously reliant on JavaScript to reproduce for keyboard interactions.
Highlighting table rows
One common example: table rows that change background color on hover. Styling like this may be implemented to help sighted users parse complex/long tables, as the visual highlight can make it easier for these user to keep track of the table row they’re currently reading. Unfortunately, without JavaScript, there was no way to do this for sighted keyboard users, until now:
The above example showcases how one can use the :focus-within
pseudo-class to highlight an entire table row, if there is at least one focusable element within a table cell of a particular row.
The most important CSS from the table example is the following:
tbody tr:focus-within,
tbody tr:hover {
background: rgba(lightBlue, .4);
}
But you can view the rest of the table example on codepen.
Support
Likely not a shocker to anyone, but :focus-within
still has a ways to go before it can readily be used on projects without any sort of polyfill. This is incredibly important to note as Keith J. Grant’s tweet explains:
Note: if a selector list contains an invalid selector, the entire list is considered invalid. Thus this doesn’t gracefully degrade: pic.twitter.com/HKJjZgp9GO
— keith•j•grant (@keithjgrant) May 9, 2017
At the time of writing, May 2017, here are the browsers that support :focus-within
, without needing to turn on experimental flags.
- FireFox 52+
- Chrome 60+
- Desktop Safari 10.1
- Mobile Safari 10.3
Fortunately, Rodney Rehm has a focus-within polyfill that you can checkout.
Link roundup:
You can check out the source code for all of the demos in this article via the listed CodePen and GitHub links below: