Style focus

The focus indicator (often signified by a "focus ring") identifies the currently focused element on your page. For users who are unable to use a mouse, this indicator is extremely important because it acts as a stand-in for their mouse-pointer.

If the browser's default focus indicator clashes with your design, you can use CSS to restyle it. Just remember to keep your keyboard users in mind!

Use :focus to always show a focus indicator

The :focus pseudo-class is applied any time an element is focused, regardless of the input device (mouse, keyboard, stylus, etc.) or method used to focus it. For example, the <div> below has a tabindex which makes it focusable. It also has a custom style for its :focus state:

div[tabindex="0"]:focus {
  outline: 4px dashed orange;
}

Regardless of whether you use a mouse to click on it or a keyboard to tab to it, the <div> will always look the same.

Unfortunately browsers can be inconsistent with how they apply focus. Whether or not an element receives focus may depend on the browser and the operating system.

For example, the <button> below also has a custom style for its :focus state.

button:focus {
  outline: 4px dashed orange;
}

If you click on the <button> with a mouse in Chrome on macOS you should see its custom focus style. However, you will not see the custom focus style if you click on the <button> in Safari on macOS. This is because in Safari the element does not receive focus when you click on it.

Because the behavior of focus is inconsistent, it may require a bit of testing on different devices to ensure your focus styles are acceptable to your users.

Use :focus-visible to selectively show a focus indicator

The new :focus-visible pseudo-class is applied any time that an element receives focus and the browser determines via heuristics that displaying a focus indicator would be beneficial to the user. In particular, if the most recent user interaction was via the keyboard and the key press did not include a meta, ALT / OPTION, or CONTROL key, then :focus-visible will match.

The button in the example below will selectively show a focus indicator. If you use a mouse to click on it, the results are different than if you first use a keyboard to tab to it.

button:focus-visible {
  outline: 4px dashed orange;
}

Use :focus-within to style the parent of a focused element

The :focus-within pseudo-class is applied to an element either when the element itself receives focus or when another element inside that element receives focus.

It can be used to highlight a region of the page to draw the user's attention to that area. For example, the form below receives focus both when the form itself is selected and also when any of its radio buttons are selected.

form:focus-within {
  background: #ffecb3;
}

When to display a focus indicator

A good rule of thumb is to ask yourself, "If you clicked on this control while using a mobile device, would you expect it to display a keyboard?"

If the answer is "yes," then the control should probably always show a focus indicator, regardless of the input device used to focus it. A good example is the <input type="text"> element. The user will need to send input to the element via the keyboard regardless of how the input element originally received focus, so it's helpful to always display a focus indicator.

If the answer is "no," then the control may choose to selectively show a focus indicator. A good example is the <button> element. If a user clicks on it with a mouse or touch screen, the action is complete, and a focus indicator may not be necessary. However, if the user is navigating with a keyboard, it's useful to show a focus indicator so the user can decide whether or not they want to click the control using the ENTER or SPACE keys.

Avoid outline: none

The way browsers decide when to draw a focus indicator is, frankly, very confusing. Changing the appearance of a <button> element with CSS or giving an element a tabindex will cause the browser's default focus ring behavior to kick-in.

A very common anti-pattern is to remove the focus indicator using CSS such as:

/* Don't do this!!! */
:focus {
  outline: none;
}

A better way to work around this issue is to use a combination of :focus and the :focus-visible polyfill. The first block of code below demonstrates how the polyfill works, and the sample app beneath it provides an example of using the polyfill to change the focus indicator on a button.

/*
  This will hide the focus indicator if the element receives focus via the
  mouse, but it will still show up on keyboard focus.
*/
.js-focus-visible :focus:not(.focus-visible) {
  outline: none;
}

/*
  Optionally: Define a strong focus indicator for keyboard focus.
  If you choose to skip this step, then the browser's default focus
  indicator will be displayed instead.
*/
.js-focus-visible .focus-visible {
  …
}