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:

Default focus indicator in Chrome
Default focus indicator in Chrome

That said, there are some issues with the default browser behavior:

Hence, let’s go through different ways to implement a custom focus indicator.

Implementation techniques

Custom outline

Most browsers use the outline property to highlight the focused element. You can customize it with the :focus selector:

:focus {
outline: #0f64ce solid 2px;
}
Custom outline
Custom outline

That’s a good start. Unfortunately, outline does not provide a cross-browser way for rounded corners:

Focus indicator on a round button
Focus indicator on a round button

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):

:focus {
outline: #0f64ce solid 2px;
outline-offset: -2px;
}
Custom outline with a negative offset, overlapping rounded corners
Custom outline with a negative offset, overlapping rounded corners

Box Shadow

Using a box-shadow instead of an outline provides more styling possibilities:

:focus {
outline: 0;
box-shadow: 0 0 0 2px hsla(210, 100%, 50%, 0.5);
}
Focus indicator using box-shadow
Focus indicator using box-shadow

However, box-shadow is hidden in the Windows High Contrast mode, so we have to provide a proper fallback:

:focus {
outline: transparent solid 2px;
box-shadow: 0 0 0 2px hsla(210, 100%, 50%, 0.5);
}

Pseudo-element

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.

:focus {
position: relative;
}

:focus::after {
content: "";
outline: 2px solid hsla(210, 100%, 50%, 0.5);
position: absolute;
top: -4px;
right: -4px;
bottom: -4px;
left: -4px;
z-index: 99999;
}
Focus indicator using an ::after element
Focus indicator using an ::after element

Background color

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.

Default Firefox focus ring

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:

Custom focus ring in Firefox
Custom focus ring in Firefox

In that case you might want to disable this vendor property:

::-moz-focus-inner {
border: 0;
}

General tips

  • 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.

Related posts