Introduction
CSS Focus states might seem straightforward, but in reality, there are multiple selectors that control how and when focus is displayed on elements. There are three primary focus states in CSS, plus a “secret” fourth one.
Understanding how to use these focus states correctly can elevate accessibility, create smoother interfaces, and improve user navigation.
Try playing with these examples below by tabbing or clicking and see the differences:
The focus will show every time, whatever method is used.
The focus won’t show on click, but it will show with every other method.
The focus will show on the parent element, whatever method is used.
The focus won’t show on click, but it will show with every other method.
Note: If you are on a mobile device, you won’t see anything happening. Come back on a computer to have functionnal interactive examples. :)
Now that you have a basic understanding, let’s deep dive into this :focus
universe to see when and where to implement them.
The basic :focus state
The simplest of all focus states is :focus
.
a:focus {
outline: 2px solid deeppink;
}
When you apply this to an element, it shows a style whenever that element is focused.
The focus can occur from clicking, tabbing, or using other navigation methods.
For example, if you tab through this site, you will see a black or white (depending on dark mode) outline on links and buttons.
But if you try to click on any buttons or links, it won’t show anything.
Why you ask?
Because, for this site, I used :focus-visible on almost all the links!
The :focus-visible state
Unlike :focus
, which shows styles regardless of how the user interacts with the element, :focus-visible
only displays focus styles when they’re visually necessary.
a:focus-visible {
outline: 2px solid deeppink;
}
For instance, when navigating by keyboard, :focus-visible
triggers, but with a mouse, it won’t display any outline.
This keeps the interface looking clean, while still offering guidance for keyboard users.
So, how do you decide between :focus
and :focus-visible
?
Here’s my rule:
- Use
:focus
if you want a style that shows up with any type of interaction. In general all inputs related to a form. - Use
:focus-visible
for a cleaner look, where focus only appears when helpful for the user. In general, for all other types of elements (links, buttons, etc.).
If you noticed on my website, the only element that have a simple :focus
state is the input of my newsletter. Everything else uses :focus-visible
.
Now that we’ve reviewed the 2 basic focus states, let’s dive into the advanced state :focus-within
.
The advanced :focus-within state
Another useful focus state is :focus-within, which allows you to style a parent element based on whether any child element inside it is focused.
.container:focus-within {
outline: 2px solid deeppink;
}
This is especially useful for complex components like dropdowns or modal containers.
This will trigger for each user interaction on the selected area (click, tab, or other navigation methods).
The focus will show on the container every time the user focuses on an element inside it. even a link or an input
For now we reviewed :focus
, :focus-visible
and :focus-within
.
So, the next state to present is logically :focus-within-visible
, right?
Well, almost, but not excatly. Here is this fourth secret state!
The “secret” fourth :focus-visible-within state
While CSS doesn’t directly support a focus-visible-within
selector, you can achieve this effect using the :has
pseudo-class.
.container:has(a:focus-visible, button:focus-visible) {
outline: 2px solid deeppink;
}
This “secret” selector applies the focus only when it’s necessary for the user’s navigation style, similar to :focus-visible
, but within a container context.
By combining :has
with :focus-visible
, you can set up a container element to style itself based on the visibility of focus within its child elements.
This is particularly useful for custom interface elements, where a parent container needs to indicate focus only in visually relevant scenarios.
The focus will show on the container every time the user focuses on an element inside it, but not when it’s a mouse click. Try with a link or an input
Support My Work
Feel free to leave your comments or questions via email at hey@theosoti.com.
If you found this article helpful, please share it with your peers and join my newsletter below for more web development tutorials.
Happy coding!