Web accessibility is one of those things that software projects often neglect. In this article, I’d like to raise the awareness by exploring the focus indicator.
When navigating a website using a keyboard (whether I want or have to), I should be able to see which element is currently focused. Otherwise, things like filling out forms would be a nightmare. Yet, around half of the UI frameworks I’ve tested do not provide a sufficient focus indicator.
That’s surprising, because every browser provides a native focus ring:
That said, there are some issues with the default browser behavior:
- Browsers use different styles.
- The background color may be too similar to the focus ring’s style, making it hard to see.
- Placing a focusable element into an
overflow: hiddencontainer may lead to the focus indicator not being displayed.
Hence, let’s go through different ways to implement a custom focus indicator.
Most browsers use the outline property to highlight the focused element. You can customize it with the
That’s a good start. Unfortunately,
outline does not provide a cross-browser way for rounded corners:
It doesn’t look awful, but it isn’t pretty either. One workaround is to define a negative offset using
outline-offset, that will overlap the border corners (unless you have to support IE11):
box-shadow instead of an outline provides more styling possibilities:
box-shadow is hidden in the Windows High Contrast mode, so we have to provide a proper fallback:
Last but not least, you may try using an
::after pseudo-element. It provides even more customization options, at the cost of being more difficult to implement reliably.
Another common focus indicator pattern is to replace the outline with a background color change on focus. The upcoming WCAG 2.2 update addresses this pattern by defining the required terms. If no focus ring is being used, the contrast ratio between the color and focus color has to be at least 3:1.
While this approach makes a component WCAG-compliant, I still recommend using a focus outline, as it makes it easier to locate a focused item.
For some reason Firefox does not use
outline as the default focus indicator. Instead, you will see a dotted black border. If you decide to use a custom focus ring, it may look strange:
In that case you might want to disable this vendor property:
You might want to display the focus ring for keyboard users, while hiding it on mouse click. There are pros and cons of this approach, but you can achieve this behavior with the
:focus-visible pseudo-class (MDN docs). For older browsers, you can either include a polyfill or use progressive enhancement:
The duplicate focus style definition is necessary because
:not doesn’t have any effect on CSS specificity, so we’re relying on the rule order here.
- Do not remove the default browser focus indicator without providing an alternative, unless you don’t like your users.
- Provide a sufficient alternative. Using a different background color shade is not sufficient in my opinion, as it’s difficult to identify such a focus indicator when the element stands on its own.
- Make sure the contrast ratio between the focus ring color(s) and both the text and background colors passes WCAG Level A (3:1 contrast ratio).
- You may have to use multiple implementations for different elements to make it always look nice and accessible.