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

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.
  • You may have to use multiple implementations for different elements to make it always look nice and accessible.

Related posts