Is it time for :focus-visible?

CSS pseudo-class that helps to display focus indicator only when a user needs it

By
  • Taras Rodynenko
Jun. 30 20235 min. read time
focus-visible-intro.png

Nowadays accessibility (a11y) has become an essential consideration when designing and developing websites and applications. Ensuring that everyone can access and navigate digital content is not only a legal requirement in many countries, but also an one of the fundamental principles of inclusivity. The ability to identify and interact with interactive elements using keyboard navigation on a website is one of the aspects of web accessibility. And here CSS pseudo-classes like :focus or :focus-visible come into play.

From a first look :focus and :focus-visible are doing the same by helping the user to highlight interactive elements. On the other hand, :focus-visible takes in count real user needs. Because, when reading the definition spec, it sounds like :focus-visible makes User Experience better, more personalised. So should we only use :focus-visible instead of just :focus in our web applications and websites?

Overview

Before we make any choices, let's remind us first what is CSS pseudo-class :focus-visible, and what the difference from regular :focus is.

Definition

The :focus-visible pseudo-class is defined in Selectors Level 4 specification. It applies while an element matches the :focus pseudo-class AND the browser / user agent determines that the focus should be made evident on the element. Many browsers show a "focus ring" by default in this case. via MDN

So now browsers get opportunity to decide WHEN they should show the focus indicator, based on user characteristics, or importance. In other words :focus with condition.

But as usual, it is quite tricky to find out when browsers actually apply a condition to it. It seems we can split the process in 4 steps:

  1. Has the user expressed a preference for always visible focus?
  2. Does the focused element support keyboard input?
  3. Is the user interacting with the focused element with a non-pointing device?
  4. Did a script cause focus to move from a previously visibly-focused element?

Recommend to follow the link above to read about each of the steps in more details. But I also want to sum up: It's only in rare cases where :focus-visible not gets applied. For example, when a user interacts with a website on touchscreen or by mouse.

🗣️ In my point of view, the behaviour of :focus-visible opens up the opportunity to forget about famous CSS anti-pattern :focus { outline: 0; }, which is very bad for accessibility. Designer will not see anymore unwanted focus styles on active elements after mouse click, or on mobile, by default.

Browser support

The browser support is good: all main "evergreen browsers", if you look on the latest versions. Safari was the last one, and it has begun support only from version 15.4 (March 2022). It is interesting that :focus-visible was brought into Webkit (Safari) by Igalia, an independent vendor.

Used in the wild

As we can see from WebAlmanac 2022, the amount of websites that are using:focus-visible grew enormously from 0.6% to 10% in one year, so let's see what is happening around.

Browser defaults

All major browsers have already changed their default user agent stylesheets from :focus to :focus-visible. You can test focus-visible styling in DevTools. And as we can see there, browsers trigger focus and focus-visible as independent events.

/* Chrome, Edge */
:focus-visible {
	outline: -webkit-focus-ring-color auto 1px;
}

/* Firefox */
:focus-visible {
	outline: 1px auto;
}

/* Safari */
:focus-visible {
	outline-color: -webkit-focus-ring-color;
	outline-style: auto;
	outline-width: 5px;
}

There are no more default styles for :focus.
👀 You can check this on any HTML only website, like the First HTML website(The WWW project). And in DevTools check :focus to simulate.

In Safari v16 (tested in 16.3 and 16.5) there is a bug: you need to check both :focus and :focus-visible to simulate focus-visible styles.

Libraries

For me, an important criterion of spreading and adopting CSS techniques is the use in popular UI libraries and frameworks. They give developers a predefined setup that is not often changed. Also, they are good for the initial start and fast growth of the project.

For a such case, we can look at the CSS frameworks list from State of CSS 2022. Of course, it is not all market, but at least we can find out if there is any work on the focus-visible adoption.

Nevertheless, Safari added support only in March 2022 - the frameworks like Tailwind, Bootstrap, Ant Design, and UIKit are already using focus-visible in the latest versions (4 of 10, if we look at the first ten mentioned in the list).

So, some UI libraries also are going the way to replace :focus styles with :focus-visible. As for me, it is a good sign.

The need for more control on focus styles

Additionally, I'd like to highlight another option that we as developers have. We can "take" control on when we want to show focus styles from the browser.

DNB has its own design system and open-sourced component library, called Eufemia. So, everyone can investigate what components Frontend teams are using to create web applications.

But, in this article, I'd like to look at the way Eufemia defines styles for focus state. In case of Eufemia, the library takes full control of showing focus styles by tracking what input type the user is using. And based on this knowledge it forces specific styles, if needed.

Code snippet with simplified example:

html:not([data-whatintent=touch]) .dnb-button:focus { 
	/* focus styles for NOT touch input */
}
html[data-whatinput=keyboard] .dnb-button:focus {
	/* focus styles for keyboard */
}

⚠️ Here you are the boss, and you take all responsibility for user experiences in all situations, like opening a website with turned-off JavaScript. Some downsides could be an additional dependency on JavaScript (some library or internal logic) and selectors' complexity, but it gives freedom and controlled expected behaviour.

A similar technique is used in Adobe Spectrum CSS and Material UI. Where a special class like focus-ring or ...-focusVisible is added when the user should see focus indicator on an element.

Parallel usage

Okay, imagine, you see the benefits of :focus-visible, but still need a fallback for the old and good :focus. It is still possible, because we are in CSS magic world 🪄.

:focus {
	/* your beautiful styles */	
}
:focus-visible {
	/* duplicate your beautiful styles */
}

:focus:not(:focus-visible) {
	/*
		But you will need to reset focus styles 
		for browsers with support;
	 */
	/*
		Other browsers will skip this selector,
		because it is broken for them;
	*/
}

Also, this code snippet can prevent you from unexpected browser's behaviour, when it can apply :focus without :focus-visible.

Summary

For browsers, it doesn't matter which focus CSS pseudo-class you use. And from an accessibility perspective, it's already great that you cover such behaviour and help with keyboard navigation. It seems that your choice (or a team's choice) between :focus and :focus-visible depends on who your users are and what experience you prefer to give them.

But - I hope your users do not continue using IE11 🙏. If they still do, then you do not have a real choice 😔 - although you could offer backward compatibility. But it comes with higher code complexity, which may suffer the user experience over time.

Personally, I believe you should consider using :focus-visible for new / small projects, and extend this behaviour to other projects when browser support will allow it. But, nevertheless, :focus always will be a hero 🦸. As we know Web is designed to be backwards compatible (W3C)

  • UX
  • Accessibility
Disclaimer: The views and opinions expressed in this article are those of the author and do not necessarily reflect the official policy or position of DNB.

© DNB

To dnb.no

Informasjonskapsler

DNB samler inn og analyserer data om din brukeratferd på våre nettsider.