DEV Community

Codeguage
Codeguage

Posted on • Originally published at codeguage.com

What is the Difference Between :focus, :focus-visible, and :focus-within in CSS?

Table of contents


As you may know, there are three similar sounding pseudo-classes in CSS, namely :focus, :focus-visible, and :focus-within.

At the first glance, one might get confused about the difference between these and when to use which one. The good news is: these three pseudo-classes are extremely simple to understand and distinguish from one another.

In this article, we shall understand what exactly is :focus, :focus-visible, and :focus-within, and when and how to use each one of these pseudo-classes.

Further reading:
If you need a refresher on pseudo-classes, hop over to the chapter CSS Pseudo Classes, in our CSS course.


The :focus pseudo-class

First things first, the :focus pseudo-class applies to an element when it's focused.

This focus can be made using the mouse (when we click on the element), the keyboard (when we navigate to it by pressing Tab), or the underlying program (when we use JavaScript).

Further reading:
You can explore the :focus pseudo-class in detail in CSS Pseudo Classes: :focus.

Furthermore, only focusable elements are allowed to receive focus and, therefore, be the subject of :focus. These are typically interactive elements in HTML — the likes of <input>, <textarea>, <button>, and so on.

💡 Notice: Non-interactive elements such as <p>, <h1>, <blockquote>, <code>, etc., aren't focusable and therefore can't be the subject of :focus. It's only if we explicitly make them focusable, by setting the tabindex attribute on them, that we can expect :focus to apply to them.

Coming back to :focus, this pseudo-class is used to select and, thereafter, apply styles to elements when they are in the focused state.

Perhaps, the most naive example of doing so would be to consider an input field as demonstrated below:

<label>
   <span>Name</span>
   <input type="text" name="name">
</label>
Enter fullscreen mode Exit fullscreen mode

Live Example

The moment we click on the input field, it receives focus and, consequently, the browser applies a black outline to it, as illustrated below:

The input field focused

This helps us immediately see which input are we currently in within a form of many input fields.

To better appreciate the benefit of this, imagine the opposite. Suppose we click on an input field and have no special styling applied to the field as we do so.

What do you think, would it be possible for us to determine which input are we currently in? Well, it clearly won't be impossible to do so but NOT that quick either.

The ideal thing in designing user interfaces of any kind is to 'make everything as easy as possible.' And in this case, this ideal world can very easily be achieved just by employing the :focus pseudo-class.

In essence:

The :focus pseudo-class (even the other two focus pseudo-classes) helps us improve the accessibility of a webpage.

By clearly communicating to the user visually as to where he currently is on the webpage, we make it easy enough for him to interact with the webpage and get his work done without any confusion.

In other words, :focus is more important of a pseudo-class than we might think it is.

But it's not the only important focus-based pseudo-class; we have :focus-visible as well.


The problem with :focus

In the example above for :focus, we considered a basic, text input field. Let's now shift to a button in order to see a shortcoming of :focus.

Consider the following button, with the added :focus rule for it:

<button>A button</button>
Enter fullscreen mode Exit fullscreen mode
button:focus {
   outline: 3px solid blue;
}
Enter fullscreen mode Exit fullscreen mode

Live Example

The moment we click on the button, we get the desired blue outline, as illustrated below:

The button focused

But wait a second? Is this desire of us desirable?

Said another way: Is it a wise decision to showcase the outline when we click on the button using the mouse? As it turns out, NO, it's not!

Let's understand why...

When we click on a button — or any interactive element, in general, that is meant to perform an action, for e.g. a link — we already know where we are on the webpage. Obviously, because we click consciously on the button, we certainly can't be confused about which element on the webpage currently has focus — we clearly know that it's the button we just clicked that has the focus currently.

In this respect, it does NOT make much sense, if at all, to visually emphasize the button to be the currently focused element.

But why does this make sense for input fields?

Good question. You're right in your observation that :focus works absolutely fine when we use it on input fields and there's a simple reason for it. When we click on an input field using the mouse, our job doesn't finish; we still have to enter data into the field.

And because our work isn't done yet, we quickly and clearly need to know which input is currently active.

Most importantly notice the important, yet subtle, distinction between input fields and buttons (and other suchlike interactive elements):

  • An input field doesn't accomplish a task immediately and therefore requires focus to be visualized even when we use the mouse to interact with it.
  • A button accomplishes a task immediately (for e.g. adds an item to a cart) and therefore doesn't pose the need to visually showcase it in its focused state when we interact with it using the mouse.

So, at this point, we know that input fields gel nicely with the :focus pseudo-class but that's not the case with buttons.

But keep in mind that this reasoning only applies to when we interact with these elements using the mouse. What happens when we shift to a keyboard?

Let's find out...


Interactions using the keyboard

As you may know, it isn't only possible to navigate around a webpage using the mouse; we can use the keyboard for this as well, and equally well.

In fact, if a webpage is built this way to only entertain mouse interactions, it's extremely inaccessible.

Imagine someone broke their mouse device and now wants to prepare for their exam, and that there's no way to order another one at the moment. The worst case would be if that person wanted to prepare from a website built only around mouse interactions.

As CSS developers, we must acknowledge this fact and design websites to be as accessible without a mouse as with it. In this respect, we must make sure to provide necessary visual emphasis on interactive elements when they receive focus.

And this now includes buttons as well.

Let's state this again.

When we're using the mouse to interact with a webpage, creating visual emphasis for buttons (and similar elements) in their focused state isn't necessary; in fact, it's undesirable as we saw above. This is because the user already knows that after clicking on the button, it is the one that comes in focus.

But when we're using the keyboard instead, creating visual emphasis is utmost necessary. This is because, now, the user isn't aware of which interactive element is in focus. We need to visually showcase this.

The problem is that we can't use :focus for this styling concern because... well... it applies to button even when we interact with them using the mouse.

Now what?

No need to worry, for we have :focus-visible to the rescue!


The :focus-visible pseudo-class

I stress a lot on the fact that before getting to learn anything in programming, first gaze over its nomenclature (a fancy word for 'naming'). Chances are high that the meaning lies in the name itself.

Following this, if we analyze the name :focus-visible, it clearly has something to do with 'focus' but also something to do with 'visible'.

Can you figure out just by the name what this pseudo-class means?

Well, :focus-visible applies to an element that is in focus and whose focus needs to be made visible (ideally). Compactly, we could also say that :focus-visible applies to an element that ought to have its focus visible.

:focus-visible only shows up when we bring an element in focus using the keyboard, or some other non-mouse interaction (for e.g. using JavaScript).

Most importantly — and this is really really important — :focus-visible does NOT apply to buttons (and suchlike elements) when they receive focus by virtue of mouse interactions.

With this, let's go back to our <button> example above and replace the :focus rule with :focus-visible so that the outline is only presented when the button receives focus via the keyboard:

button:focus-visible {
   outline: 3px solid blue;
}
Enter fullscreen mode Exit fullscreen mode

Live Example

Here's what we get when we click on the button (using the mouse):

The button (with a :focus-visible style) focused again

Nothing.

But when we press the Tab key in order to navigate to the button and bring it in focus, we get the same outline as before:

The button focused via the keyboard

This brings us right at the ultimate conclusion that when styling buttons (or other suchlike elements, for e.g. <a>), we must preferably use :focus-visible instead of :focus (for reasons we saw above).

:focus-visible is basically a win-win situation in that (a) we don't apply styles when buttons are clicked, and therefore focused, using the mouse and (b) we do make sure that our webpage remains accessible when using the keyboard with necessary focus styles on buttons.

:focus-visible is a hero! (But I don't know the movie's name!)


What about :focus-within?

Obviously, we couldn't end this article without going over the less useful :focus-within pseudo-class. Let's do that now.

:focus-within, as the name suggests (remember to read names carefully), applies to an element that has focus within it.

In other words, any element that contains a descendant element that matches :focus, or itself matches :focus, is a candidate for :focus-within.

Following is an example:

<div>
   <p>This is a paragraph</p>
   <button>A button</button>
</div>
Enter fullscreen mode Exit fullscreen mode

We have a button contained inside a <div>. Our goal is to style the <div> specially when its button is in focus. The following CSS accomplishes this:

div:focus-within {
   background-color: pink;
}
Enter fullscreen mode Exit fullscreen mode

Live Example

The moment the button receives focus, the <div> gets a pink background color.

Pretty basic.

💡 Notice: Keep in mind that :focus-within behaves exactly like :focus in that it also shows up on mouse interactions on buttons, for example. It does NOT exhibit a behavior similar to :focus-visible.

Now you might be looking for a more practical example of :focus-within and that's precisely what I have up next for you.

As stated earlier, :focus-within isn't that commonly used in CSS but some cases are such that they can be solved pretty elegantly using :focus-within. Read on to learn about such a case.

Practical use case for :focus-within

Suppose we have an accessibility bar on a website that only shows up when using keyboard navigation. Initially, it's hidden but only visually; that is, it's possible to tab to either of the buttons inside this bar.

💡 Notice: 'Hidden only visually' means that the element doesn't have display: none or visibility: hidden set on it to otherwise actually hide it. For instance, opacity: 0 hides an element only visually.

Now, the moment any of the buttons in this accessibility bar comes into focus, it's required to showcase this bar to the user.

But how to select the accessibility bar when either of its buttons has focus? Well, supposing that the bar can be selected by the class selector .a11y-bar ('a11y' is a short form for 'accessibility'), the desired selector would be .a11y-bar:focus-within.

.a11y-bar:focus-within selects the .a11y-bar whenever focus resides within it, which is exactly what we need.

Good job!

The link below demonstrates this example:

Live Example


Further reading

Despite the fact that we've covered almost everything that we need to know about :focus, :focus-visible, and :focus-within, there still is value in reading further from some resources as mentioned below:


Learn CSS today

If you're a newbie in CSS and want to learn the basics well, consider the CSS course on Codeguage.

Top comments (0)