SOUEIDAN

A guide to designing accessible, WCAG-compliant focus indicators

This post is a modified, text-only excerpt from my Practical Accessibility video course. I wanted to share this guide to designing accessible focus indicators because focus styles are a recurring discussion I have with designers I work with on most projects, so I thought it would be useful to provide this guide as a helpful reference. This guide is aimed at both designers who want to learn about accessibility considerations for designing focus indicators, as well as developers who want to implement them.


Imagine you visit a Web site and you want to browse it for some content. You want to buy something; or maybe book a flight somewhere. And as you move your cursor onto the page, it suddenly disappears. Your hand may be still on the mouse, and you’re moving the mouse across the screen and across the page; but you can’t see where it is. You may or may not be hovering over a link or a button or any other form control at any moment. But if you are hovering over one, you don’t know which one it is. You could try clicking and then finding out, but you can probably already imagine what a nightmare of an experience you’re about to get into.

Unfortunately, keyboard users experience the Web in a similarly frustrating manner too often. Their equivalent of a mouse cursor is usually hidden on too many Web sites, making it almost impossible for them to navigate those sites. A keyboard user’s cursor equivalent is the focus indicator. By designing and implementing accessible focus indicators, we can make our products accessible to keyboard users, as well as users of assistive technology that works through a keyboard or emulates keyboard functionality, such as voice control, switch controls, mouth sticks, and head wands, to mention a few.

What exactly is a focus indicator?

Keyboard users typically navigate their way through Web sites by pressing the tab key. This allows them to jump from one interactive element on the page to another.

Just like mouse users, they need to be able to see where they are on a page as they Tab their way through it, otherwise they won’t be able to identify the elements they are interacting with. That’s what focus indicators are for.

A focus indicator is a visual indicator that “highlights” the currently focused element. This visual indicator is commonly presented as an outline around the element. An outline takes the shape of its element, and since every element in CSS is a rectangle, an outline is, therefore, usually a rectangle drawn around an element.

Navigating the Mozilla Developer Network (MDN) Web site using a keyboard. As you tab through the homepage, you can see a rectangular outline highlighting the currently focused element.

A focus indicator can also take other forms, but outlines are very common for several reasons. Outlines have an advantage over other visual indicators (such as borders or background colors, for example) in that they can be applied to the element without causing any significant changes to that element. And since an outline is not part of an element’s box model, it does not affect the layout of that element, and will therefore not cause any layout shifts when it is applied. (That’s also why outlines are preferred over borders for visualizing and debugging layouts 💡) In addition to that, outlines are preserved and used in Forced Color Modes such as Windows High Contrast Mode, where background colors, border colors, and box shadows are usually overridden by user and system styles.

So a focus indicator allows a keyboard user to see exactly where they are at any given moment. Without it, they wouldn’t know where they are on a page and they wouldn’t be able to navigate the page and operate its controls.

The focus indicator is to keyboard users what the mouse cursor is to mouse users. And just like you would never want to hide the mouse cursor, you never want to hide the focus indicator.

Laura Carvajal on stage at Fronteers 2018, with a slide on screen behind her that says 'You wouldn't steal their cursor'
Laura Carvajal on stage at Fronteers conference 2018.

In fact, a visible focus indicator is a requirement for a site to be considered accessible under the Web Content Accessibility Guidelines (WCAG). Removing or hiding focus indicators is a violation and will therefore fail Success Criterion 2.4.7: Focus Visible (Level A), which states that any keyboard operable user interface has a mode of operation where the keyboard focus indicator is visible.

Browser default focus styles

Browsers provide focus indicators to native interactive elements out of the box, for free. And most of us—if not all—have at some point in time included this CSS snippet in their stylesheets:


:focus {
	outline: none;
}

to remove those focus indicators applied by the browser.

To meet the accessibility requirement, you should avoid removing the focus indicator provided by the browser unless you are replacing it with your own focus indicator. And I do recommend you do that.

By preserving browser focus styles, you may meet the requirement of showing a visible focus indicator, but that may not be enough, because a focus indicator needs to be clearly visible to be considered accessible. And browser focus indicators may not always be.

(What’s the benefit of showing an indicator that many users may not be able to see?)

In order for a focus indicator to be clearly visible it needs to have a color contrast against adjacent colors that is high enough for users with moderately low vision to be able to discern it.

The Web Content Accessibility Guidelines define the minimum color contrast ratio required for interactive components and their states to be accessible in Success Criterion 1.4.11 Non-Text Contrast.

Focus indicators on UI controls fall under the “non-text” components category, as they are used to identify a component’s state. To pass this criterion, our focus indicators must have a color contrast ratio of at least 3:1 against adjacent colors.

Default focus indicators provided by browsers may fail this criterion, depending on the colors you’re using on your page. You can end up with a usability problem if the colors of your page clash with the colors of the default focus indicators, making them difficult to see. When that happens, you’ll want to override those focus styles with better, more accessible ones.

Here is a screenshot of how Chrome, Firefox, Microsoft Edge, and Safari style their respective focus indicators (at the time of writing) when applied to a button:

Screenshot showing a blue button on a white background with four different focus indicators as applied by Chrome, Firefox, Edge, and Safari.

Chrome, Edge and Safari apply a 1-pixel solid outline. Firefox applies a 1-pixel dotted outline. As far as color contrast with the white background goes, they all pass the accessibility check. But the dotted outline in Firefox is still very difficult to discern compared to the other outlines, even though its color has enough contrast with the white background. This is because the contrasting area of the outline is not large enough. And that’s because the outline is very thin and dotted. We’ll come back to this shortly.

On a black background, Firefox’s black focus indicator disappears, and Safari’s indicator has a contrast so low it will be extremely difficult to discern by most users.

Screenshot showing the blue button on a black background with four different focus indicators as applied by Chrome, Firefox, Edge, and Safari.

Chrome and MS Edge, however, have something interesting happening in that they apply what looks like a second outline—a while outline around the first outline, that creates enough contrast on most darker backgrounds.

So while you may get away with using the default browser focus styles to meet WCAG 2.1 requirements and call it a day, it is generally a good idea that you override the default styles with more accessible ones. In fact, in WCAG 2.2, it becomes necessary to do that, because the requirements get more specific, and as you’ll see in the following sections, browser focus indicators will often fail the new requirements.

In what follows, we’re going to get a little nerdy!

Note: WCAG 2.2 is currently a working draft. So the concepts and requirements we're going to cover in this article may change in the future. I’ll keep this article up-to-date with any future changes should they happen.

New focus indicator accessibility requirements in WCAG 2.2

In WCAG 2.2, two success criteria were added to define how accessible a focus indicator is depending on both its color and area:

Both of these new criteria aim to ensure that a keyboard focus indicator is clearly visible and discernible, and they provide the conditions to ensure that. These criteria specify the minimum area required for the focus indicator to be considered visible, taking into account its color contrast ratio—relative to its initial color as well as adjacent colors within the focused component. We’ll dive deeper into what exactly this means in a few seconds.

2.4.12 is the AAA level of 2.4.11—it sets a higher bar and it builds upon it. It aims to ensure the focus indicator is highly visible by defining an even higher level of visibility requirements.

In what follows, we’ll examine what the Level AA criterion 2.4.11 requires for focus indicators to be considered accessible.

1. The focus indication area and the contrasting area

When a component changes on focus to include a focus indicator, that change can always be measured as a change of color contrast.

For the following examples, we’ll be looking at a blue button set on a white background and examine the requirements for different focus indicators to be accessible.

If you add a black outline around the blue button, the change of color between the unfocused and focused states is from white to black. That’s because the area—the pixels on the screen—that has changed color in the focused state is the area around the button. That area was initially white, and it changed to black when the button received focus. This area is called the focus indication area.

Illustration: On the left is a blue button with a white label in its default, unfocused state. In the middle is the blue button with a thick black outline around it. On the right, is a button with the same outline but with a pattern applied to it, indicating that this patterned area is the focus indication area.

The focus indication area is the area in square CSS pixels where the change in color contrast between the focused and unfocused states of the component happens.

2.4.11:Focus Appearance (Minimum) requires that there be an area of the focus indication area (a subset of the focus indication area) that has a minimum contrast ratio of 3:1 between the colors in the focused and unfocused states. That area is called the contrasting area.

In other words, the contrasting area is the area (subset) of the focus indication area that has at least a 3:1 contrast ratio with the colors of the unfocused state. And the contrasting area may or may not be equal to the entire focus indication area.

In the previous example, the color change happens from a solid white to a solid black, and the color contrast ratio between the unfocused and focused state (white and black) is 21:1. So the entire focus indication area meets the minimum contrast requirement and is therefore the contrasting area.

Illustration: On the left is a blue button with a white label in its default, unfocused state. In the middle is the blue button with a thick black outline around it. On the right, is a button with the same outline but with a pattern applied to it, indicating that this patterned area is the contrasting area.

Similarly, if you add a black outline that is separated from the button, once again, the area that exhibits the change in color is the contrasting area.

Illustration: On the left is a blue button with a white label in its default, unfocused state. In the middle is the blue button with a separated thick black outline. On the right, is a button with the same outline but with a pattern applied to it, indicating that this patterned area is the contrasting area.

I like this pattern because it adds some breathing room and helps the focus indicator stand out, making it easier to see.

If you add an outline inside the button itself, the contrasting area then lies inside the button. The change of color is from blue—the button’s background color—to black. The color contrast ratio between the focused and unfocused state is 4.86:1.

Illustration: On the left is a blue button with a white label in its default, unfocused state. In the middle is the blue button with an inner thick black outline. On the right, is a button with the same outline but with a pattern applied to it, indicating that this patterned area is the contrasting area.

If the button changes its background color on focus, then the entire button’s background area is the contrasting area, and the color contrast ratio between the focused and unfocused state is once again 4.86:1.

Illustration: On the left is a blue button with a white label in its default, unfocused state. In the middle is the button in its focused state, having a black background instead of blue. On the right, is a button with with a pattern applied to its background area, indicating that this patterned area is the contrasting area.


So, to quickly recap:

2.4.11:Focus Appearance (Minimum) of the WCAG requires a minimum contrast ratio of 3:1 between the unfocused and focused state colors of the focus indicator’s contrasting area. (That’s a mouthful, I know.)

If the component has a focus indication area with a contrast ratio is higher than 3:1, it passes the first accessibility requirement:

Contrasting area: There is an area of the focus indicator that has a contrast ratio of at least 3:1 between the colors in the focused and unfocused states.

When the focus indicator is a solid color, measuring the color contrast ratio in the contrasting area is straightforward. But color changes may not always be solid. You may want to indicate focus on the button by applying a gradient drop shadow to it. In this case, only the portion of the gradient with sufficient contrast (larger than 3:1) will be our contrasting area—the remaining portion that fails will not be a part of it. This is an example of when the contrasting area is smaller than the total focus indication area.

You may need to take some spot-checks on the gradient area and establish what area meets the contrast requirement.

Illustration: On the left is a blue button with a white label in its default, unfocused state. Next to it on the right is the blue button with a translucent black drop shadow as the focus indication area. On the right, is a button with the same drop shadow minus the parts of the drop shadow that don't pass the minimum contrast requirement, indicating that the remaining area (that does pass) is the contrasting area.

The greater the change of contrast between the unfocused and focused states, the easier it is for users to see it.

In addition to requiring a minimum contrast in the contrasting area, a focus indicator is required to have a minimum surface area for the contrasting area as well. In other words, the contrasting area needs to be large enough to be considered accessible. But how much is enough? 2.4.11 answers that in the second requirement.

2. Minimum contrasting area

Remember how we said that Firefox’s dotted outline was difficult to discern even though its contrasting area had a high contrast ratio with the background? I mentioned that that’s because its area was small, due to the outline being thin and dotted. The main issue here lies in the fact that it is dotted. The gaps in the line decrease the focus indication area, making it difficult to see.

The bigger the visible change when the component receives focus, the easier it is to see. And to ensure that focus indicators have good visibility, 2.4.11 also defines a minimum surface area for the contrasting area. So a contrasting area needs to be larger than a specified minimum.

This minimum is determined using a calculation for the perimeter of a component:

The contrasting area is at least as large as the area of a 1px thick perimeter of the unfocused component…

Illustration: On the left is the blue button with annotations for the long and short sides of the button. On the right, is the button with width and height annotations, and text that calculates the perimeter of the button: Perimeter (P) = 2*height + 2*width - 4

The perimeter of a rectangle is equal to a line that’s 2 times the width plus 2 times the height minus the shared corner pixels which are equal to 4 pixels: Perimeter (P) = 2h + 2w - 4.

The perimeter of a circle is 2𝜋r, where r is the radius of that circle.

With a minimum area in mind, we can start to examine common focus indicator patterns and specify which ones pass the criterion and which ones don’t. And we can adjust the area of those that don’t meet it to make them pass.

A 1px solid outline around a button satisfies the minimum area requirement. Because a 1px solid outline is equal to at least a 1px thick perimeter. Of course, any outline thicker than 1px will also meet the area requirement.

Firefox’s focus indicator is equal to the length of the parameter of the button minus all the gap spaces introduced by using the dotted style. The resulting length is approximately half the perimeter. To fix it, the outline thickness can be doubled to make up for the area that is lost in the gaps.

Here’s what the dotted outline looks like with 2px and 3px thicknesses. The thicker the outline, the larger its surface area, the easier it is to see.

Illustration: the blue button on the left with Firefox's default 1px dotted outline. In the middle is the same button with Firefox's dotted outline at 2px thickness. And on the right is the button with a 3px-thick dotted outline.

Now let’s assume, for demonstration purposes, that we’re designing focus styles for a 150px by 75px button. The perimeter of this button is: 150px + 150px + 75px + 75px - 4px = 446px.

When we apply an inner outline to the button, this outline is going to be smaller than the perimeter of the button (because the outline’s width and height are shorter than the button’s width and height). Once again, increasing the thickness of the outline will make up for the area lost by placing the outline inside the button.

A 130px by 55px outline inside the button will have a surface area of 366px, which is smaller than our perimeter’s 446px area. By doubling the thickness of the outline, its surface area becomes 732px, which is larger than the perimeter and therefore meets the minimum area requirement.

Illustration: On the left: the blue button with a 1px thin inner black outline. And text indicating that this outline fails. On the right: the blue button with a 2px thick inner outline, and text indicating that this outline passes.

Similarly, for any contrasting area—be it a solid outline, a part of a gradient, a background area, etc.—you’ll want to calculate the component’s perimeter and compare the focus indicator’s contrasting area to that of the perimeter.

In this following image is a circle with a 22px radius and 138px perimeter.

On the top right, the focus indicator (1) is a 1px solid circular outline. The perimeter of the focus indicator is 172px, which is larger than 138px. With a color contrast change that is higher than the minimum requirement, this indicator passes the accessibility requirement.

On the bottom left, focus indicator (2) is an inner 1px solid outline with enough color contrast change, but an area (113px) smaller than the circle’s perimeter. This indicator does not pass the requirements.

And finally on the bottom right, the focus indicator (3) is an inner 2px thick outline. This outline has a double the area of focus indicator (2) (226px), making it larger than the perimeter of the circle, so it passes the minimum area requirement.

Illustration: a circular button with a magnifier (search) icon as a visual label. Three variations of the button, each with a different focus indicator (1), (2), and (3). (1) is a 1px solid separated circular outline. (2) is a 1px solid circular inner outline. And (3) is a 3px thick inner circular outline.

In addition to the minimum area requirement that is based on the component’s perimeter, the success criterion also provides a secondary minimum based on the shortest side of the component:

The contrasting area is at least as large as the area of a 4px thick line along the shortest side of the component’s minimum bounding box, and no thinner than 2px

The bounding box of a component is the smallest possible rectangle that entirely encloses it and its descendants.

The contrasting area of the focus indicator can meet either the primary or the secondary minimum to satisfy the criterion.

Instead of aiming for a minimum area of 1px thick perimeter, you could aim for a 4px thick line along the shortest side of the component’s bounding box.

The secondary minimum area can be useful for when you have a list of focusable items stacked on top of each other, such as links in a vertical navigation or a drop-down menu. The focus indicator on a link in the drop-down could be a 4px thick border along the shortest side (typically the height) of the link as shown in the image below.

A list of vertically-stacked menu items in their unfocused state (left). On the right is the list with a 4px thick focus indicator applied to the left edge (shortest side) of one of the list items.

The thicker the line, the larger the contrasting area, the more visible the focus indicator is. Obviously, the 4px thick line along the shortest side of the element is a minimum. A bottom border along the longest side would also meet the requirement (assuming the thickness ensures a large enough area). My point is that, while I am giving simple and specific examples, my goal is to demonstrate the requirements. But you have the creative freedom to choose any focus indicator style you prefer that meets the accessibility requirements.


The main goal of the minimum area requirement is to ensure, well, a minimum area. That, in turn, aims to ensure that the focus indicator is easier to see.

I’ve talked about outlines a lot, but the focus indicator could also be as simple as an underline which has a complying minimum area, or a background color change, or a combination of a color change and a drop shadow, for example.

No matter what you choose to indicate focus, the important thing is to ensure that the contrasting area of the indicator has enough surface area that meets the WCAG requirements, so that it can be easily seen.

3. Contrast with adjacent colors in the component

In addition to requiring a minimum contrast ratio 3:1 and a minimum surface area, the contrasting area also needs to be easily distinguishable from adjacent colors within the focused component.

This is accomplished either by

  • ensuring at least 3:1 contrast ratio between the contrasting area and adjacent colors, or
  • ensuring the contrasting area has a thickness no less than 2px.

We’ll start with the blue button again as an example, and apply a simple 1px (external) outline to indicate focus. But this time, I’m changing the color of the outline from black to a darker shade of the blue used in the background.

On the left, the blue button in its default, unfocused state. On the right is the blue button with a 1px thick dark blue outline applied to it.

The button’s background color is: #314cff. And the outline color is: #1100cd.

The contrasting area color contrast ratio (dark blue versus the white background) is: 11.02:1. And its area is larger than the button’s perimeter. So the outline color and area pass the minimum contrasting area requirements that we discussed earlier.

But the dark blue color of the outline has a low contrast ratio with the adjacent blue background of the button: 1.89:1. So while this outline meets the first two accessibility requirements, it fails the third one.

To fix it, we can either

  • choose a different outline color that has at least 3:1 contrast ratio with the button’s background color (like black #000, for example), or
  • increase the thickness of the outline. Any thickness greater than or equal to 2px will do.

We can also fix the low adjacent contrast by separating the outline from the button, so the outline’s adjacent color becomes white (the background), and would therefore meet the color contrast requirement.

On the left is the blue button with a black 1px solid outline, and text that says 'Pass' underneath it. In the middle, is the blue button with a 2px thick dark blue outline, and text that says 'Pass'. On the right is the blue button with a 1px dark blue outline separated from the button's edges, and text that says 'Pass'.

By now we know that, for a focus indicator to be considered accessible, all of the following need to be true:

  • There is an area of the focus indicator that has a contrast ratio of at least 3:1 between the colors in the focused and unfocused states. This is the focus indicator’s contrasting area.
  • The contrasting area needs to be at least as large as:
    • the area of a 1px thick perimeter of the component, or
    • the area of a 4px thick line along the shortest side of the component’s minimum bounding box (and no thinner than 2px)
  • The contrasting area has a contrast ratio of at least 3:1 against adjacent colors in the focused component, or the contrasting area has a thickness of at least 2px

With these requirements in mind, we now know that Firefox’s current button focus indicator (that we saw earlier) fails the minimum contrasting area requirement. Chrome and Edge’s current focus indicators would fail the adjacent contrast requirement if your button has a background color that clashes with the outline’s color. And Safari’s focus indicator will also fail the minimum contrast ratio requirements also depending on the colors you use inside and outside the button.

These browsers may also apply different focus indicators to different interactive elements, which may (and are likely to) also fail at least one of the accessibility requirements, depending on your color palette.

So I highly recommend overriding the default focus indicators with custom, more accessible ones. This also gives you the creative freedom to design focus indicators that look nicer on your components than the ones provided by the browser.

The last requirement in this criterion is kind of a no-brainer, yet it is important to include in the success criteria because far too many Web sites fail in its regard.

4. The focused element cannot be fully obscured

The goal of a focus indicator is to allow the user to see and know where they are on a page, by making the currently active element more visible to their eye.

But what good is a focus indicator if the focused element itself is not visible because it’s hidden off-screen or obscured by other elements on the page?

The last requirement in this criterion states that the item with focus is not entirely hidden by author-created content.

Simply put: you want to make sure the user can actually see the component that they’re focusing on, by making sure it’s not hidden behind other content on the page.

2.4.11 requires that the component be “not entirely hidden”. This does imply that it could be partially hidden, as long as it’s still partially visible. 2.4.12—the AAA-level of 2.4.11—states that no part of the focus indicator is hidden by author-created content.

When aiming for Level AA conformance, you may get away with partially hiding the focused component, though I can’t imagine where or how that would not be problematic. I recommend that you always make sure focused component is entirely visible and not obscured by other content. It’s just better for usability.

You may wonder if this requirement makes Skip links inaccessible. It doesn’t. Because Skip links are designed so that they are visible when they receive focus; so the user is able to see what they are focusing on when they focus on the skip link.

A very common pattern that does fail this criterion quite often on many Web sites is off-canvas navigation and other drop-down and menu-like components.

Links in drop-down or off-canvas navigations are only meant to be clickable when they are visible. If you want to click on a link, you open the navigation, the links become visible, and you can click on the link you need and go where you need to go.

Keyboard users sometimes experience these navigation patterns differently when they are implemented inaccessibly. They’ll navigate through a page and suddenly notice their focus indicator disappear. They may continue tabbing, until at some point the indicator finally re-appears and continues to the next visible link.

This happens because the links that are hidden off-screen or inside dropdowns are only visually hidden, but are still accessible via keyboard. This results in a mismatch between the visual and keyboard experiences of a keyboard user: they’re tabbing through links and components that they are not seeing on screen.

To avoid this happening, make sure that components that are not meant to be visibly interactive are also “hidden from keyboard”, by removing them from the tab order.

To remove a component from the tab order you could:

  • hide it using CSS display: none or visibility: hidden,
  • hide it using the HTML hidden attribute,
  • set a negative tabindex value on it, or
  • make it inert using the inert attribute (currently with a polyfill)

The inert attribute comes particularly handy when you need to prevent focus on the entire page except the currently visible portion of it, like when a modal dialog or overlay is open, for example. Modal dialogs should “trap” keyboard focus so that the user doesn’t tab through elements that are currently obscured by the overlay. If users are able to tab through components on the page that are obscured by the overlay, that’s a violation of this WCAG success criterion.


Make sure to test your page using a keyboard. You can catch a lot by doing quick keyboard testing. Tab through the page and check what the experience is like. Make sure the tab order makes sense, and all tabbable components are visible when they are focused. You can track element focus as you tab through the page using JavaScript in your devtools.

It helps to visualize your tab order on the page using tools like the Accessibility Insights plugin or other accessibility testing tools that provide a similar functionality. Firefox devtools also provides an option in the Accessibility panel that, when checked, adds visual labels to interactive elements showing their tab order. Visualizing tab order helps you quickly catch tab stops that are not visible.

In the screenshot below, you can see the tab stops on MDN’s homepage. Looking at the numbers, you may notice that 1 and 2 are off-screen. That’s because the first tab stops on the page are the Skip links which are moved off-screen, and are shown when they receive focus.

The MDN homepage open in Firefox browser with the devtools open to the Accessibility tab. In the Accessibility tab, a checkbox that says 'Show Tabbing Order' is checked. And an overlay covers the page and shows the various Tab stops numbered.

So theses are the four accessibility requirements for focus indicators to pass WCAG:

  1. There is an area of the focus indicator that has a contrast ratio of at least 3:1 between the colors in the focused and unfocused states. This is the focus indicator’s contrasting area.
  2. The contrasting area needs to be at least as large as:
    • the area of a 1px thick perimeter of the component, or
    • the area of a 4px thick line along the shortest side of the component’s minimum bounding box (and no thinner than 2px)
  3. The contrasting area has a contrast ratio of at least 3:1 against adjacent colors in the focused component, or the contrasting area has a thickness of at least 2px
  4. The item with focus is not entirely hidden or obscured by other content

Both success criteria 2.4.11 and 2.4.12 measure color contrast, minimum area, adjacent contrast, and visibility. In relation to 2.4.11, 2.4.12 (Level AAA):

  • expands the minimum area to be at least double the area of a 1px thick perimeter (for example, a 2px thick outline),
  • increases the change of contrast in the contrasting area to 4.5:1, and
  • does not allow for any part of the element to be obscured by other content.

Knowing what makes a focus indicator accessible, we can examine our own as well as the focus indicators of popular design systems and UI pattern libraries, and determine which ones pass WCAG criteria and which ones don’t…

Material design button focus indicator is a change in background color, in addition to an elevation effect created by extending the box shadow underneath the button. This focus indicator fails the accessibility requirements because of a very low change in contrast (1.53:1) between the focused and unfocused states.

A button from Material Design's component library in its default unfocused state on the left, and its focused state on the right. When unfocused, the button has a navy blue background color. In its focused state, the background color becomes purple.
Material Design’s button focus indicators fail WCAG requirements for accessibility.

Bootstrap 4 buttons also fail WCAG requirements because of low change in contrast between the focused and unfocused states. For example, the change in contrast on the blue button is 1.92:1.

A screenshot of buttons from Bootstrap 4's component library in their unfocused state. Below it, is a screenshot of those buttons with their focus indicators visible. The focus indicators are 2px or 3px-thick outlines with lighter versions of the colors used in their backgrounds.
Bootstrap 4’s button focus indicators also fail WCAG requirements for accessibility.

Material UI Checkboxes get a large focus indicator area, but the color contrast change is also low (1.58:1).

On the left: a Material UI checkbox in its unfocused state. The checkbox (in its checked state) has a red background and a white checkmark. On the right is the checkbox in its focused state, showing a large focus indicator. The focus indicator is a large circle with a light red background color.
Material UI’s checkbox focus indicator fails WCAG requirements for accessibility.

GOV.UK is one of the most accessibility-compliant Web sites I know. So I was curious to see how their focus indicators measure against WCAG 2.2 requirements.

When focused, the links get a thick underline as well as a change in background color from white to yellow. While the yellow does not pass the minimum color contrast requirement, the indicator still passes accessibility requirements with the thick border compensating for that. (Note: A focus indicator that is larger than the minimum area may have parts that do not meet the 3:1 contrast ratio, as long as an area equal to the minimum does meet the contrast ratio.)

On the left, a link in its default, unfocused state. The link has a blue color and an underline. On the right is the same link in its focused state. The link's focus indicator is a yellow background color behind the text, as well as a thick black underline.
GOV.UK’s link focus indicator passes WCAG requirements for accessibility.

The text field on the GOV.UK homepage gets a 3px solid yellow outline as a focus indicator. This yellow outline has a contrast change (3.86:1) that’s higher than the requirement minimum (for a pixel color change from blue to yellow). The yellow color does not contrast with the input’s white background enough (adjacent contrast), but it is 3px thick, which compensates for that. So this focus indicator passes WCAG requirements.

On the left: screenshot of a text input as seen on the GOV.UK homepage. The background behind the content is a shade of blue. The text input has a white background and no border. On the right, the text input in its focused state. The focus indicator is a 3px thick yellow outline around the input.
GOV.UK’s text input focus indicator (on the homepage) passes WCAG requirements for accessibility.

Designing accessible focus indicators is easier now that there are specific criteria to measure accessibility against.

Showing the focus indicators only for keyboard users

The main argument I usually hear against focus styles is the fact that they appear even when you click through the page with a mouse. Designers and stakeholders both hate that. I remember a client once reporting “a bug” and telling me that mouse clicks are “kinda broken” because a thick outline appears when they clicked on links and buttons on the page. When that happens, I usually start a discussion about what focus styles are, why they are important, and why we should keep them. And then I’d always try to make a case for preserving them and “compromising aesthetics” for the sake of usability and accessibility. I didn’t always win those discussions.

Today, I have those arguments far less. While I still find myself asking for focus styles in design specs, I don’t need to “fight” for including them anymore, because today, CSS enables us to show focus styles for keyboard users and hide them for all other users. So when you click through the page with a mouse, the focus styles won’t show up and “ruin the aesthestics” anymore.

This also means that I no longer need to ask for permission to add focus styles, nor do I have to explain why they are appearing anymore. Anyone navigating the page with a keyboard will appreciate the visual aid, and those who aren’t using a keyboard won’t even know they’re there!

Browsers used to show their focus indicators on click (or tap), too. That’s why we used to include the “focus reset” rule in our style sheets.


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

Today, all modern browsers only show focus indicators when they are needed: for keyboard users. The focus outline doesn’t show up when you click or tap an element; it only shows up when you tab to it with a keyboard.

When you create your own custom focus indicators, you probably want to do the same and only show them for users who need them.

You can do that using the :focus-visible pseudo-class.

:focus-visible does exactly the same thing :focus does, except that it only applies the focus indicator styles to an element when that element receives focus via keyboard.


/* applies a black outline to links only when focused via keyboard */
a:focus-visible {
 outline: 2px solid black;
}

Browser support for :focus-visible is pretty good, but it’s not all green yet. So you may want to use the polyfill. The polyfill works by adding a focus-visible class to the focused element, in situations in which the :focus-visible pseudo-selector should match.

In your CSS, you can then use the class name added by the polyfill to target the focused element and apply the same focus styles you apply using the :focus-visible pseudo-class:


.js-focus-visible :focus:not(.focus-visible) {
  outline: none;
}

You can also skip the polyfill altogether and use :focus-visible as an enhancement on top of :focus.

In his article about :focus-visible and backwards compatibility, Patrick Lauke suggests a clever way to use :focus-visible today.

The solution Patrick suggests is to use the :not() negation pseudo-class, and to (paradoxically) define styles not for :focus-visible, but to undo :focus styles when it is absent, and then using :focus-visible if we wanted to provide additional stronger styles for browsers that support it.


button:focus { 
	/* some exciting button focus styles */ 
}

button:focus:not(:focus-visible) {
 /* undo all the above focused button styles

 if the button has focus but the browser wouldn't normally

 show default focus styles */
}

button:focus-visible { 
 /* some even *more* exciting button focus styles */ 
}

button:focus:not(:focus-visible) is CSS for “when the button receives focus that is not focus-visible”. That is, “when the button receives focus that is not keyboard focus”. In other words, “when the button receives focus that is mouse focus, for example”. When that happens, undo all the :focus styles. Then apply keyboard-only focus styles using button:focus-visible.

As Patrick notes, “this works even in browsers that don’t support :focus-visible because although :not() supports pseudo-classes as part of its selector list, browsers will ignore the whole thing when using a pseudo-class they don’t understand/support, meaning the entire button:focus:not(:focus-visible) { ... } block is never applied.”

I have a VSCode snippet set up that I use to quickly create these rulesets in my stylesheets, with sensible defaults that I find myself repeating across projects most of the time.

I’ll end this section with this paragraph from Patrick’s article (emphasis mine):

If you care about backwards compatibility (and you should, until you can absolutely guarantee without any doubt that all your users will have a browser that supports :focus-visible), you will always have to either polyfill or use the combination of :focus and :not(:focus-visible) (plus optional even stronger :focus-visible).

Tips for styling focus indicators

Focus indicators have a purpose, so do what you can to ensure that they serve that purpose well. They are meant to improve our users' experience. The user couldn’t care less about the aesthetics of focus styles as long as they help them do what they are visiting your site to do.

I like to create focus indicators that stand out. The more visible they are, the less the user needs to look for them, the better.

You can get creative and create patterned focus indicators which have that extra benefit of not relying on color alone to convey state. Just remember to make sure they meet the minimum contrast and area requirements.

We can also learn something from the way Edge and Chrome handle focus styles. Maybe create “double outlines” that play well in various color environments, or when you support both light and dark UI user preferences. In the future, the new the CSS color-contrast() function can come in handy to create a sensible default focus style for most components. In fact, color-contrast() will come in handy for a lot of accessible color design in the future.

Avoid relying on background colors and box shadows alone to indicate focus. Forced Color Modes and other accessibility display modes will override and/or remove them. Outlines, on the other hand, will not be removed and would always be visible; and the browser will apply the display mode’s custom colors to style them.

You can use backgrounds, borders and box shadows to style focus states. But if you do, add a transparent outline as a “fallback” for the various display modes:


button:focus-visible {
	/* Default. Will be removed in Forced Color Modes */
	box-shadow: 5px 5px 7px rgba(0, 0, 0, 0.1); 
	/* Fallback. Will be visible with custom system colors in Forced Color Modes */
	outline: 1px solid transparent; 
}

Focus indicators can also be animated. Background colors, borders, box shadows, and outlines can all be animated using CSS transitions and animations. The outline-width and outline-offset properties take numerical values that can be animated. So you can apply a subtle transition to your focus indicators to make them pop. Just make sure to wrap any transitions or animations in a prefers-reduced-motion user query, so users have the option to opt out of the animations if they want to.

When you’re designing and working with a color palette, you can find a color that has enough contrast with the other colors in your palette and use it to style your focus indicators. If there is no one color that meets that criterion, you can add one, or design focus styles that work for different elements and the contexts in which they appear.

You can use a color contrast tool like Stark to quickly check the contrast of two colors without interrupting your workflow — whether you’re designing in a design tool like Figma or in the browser. You can also use the browser devtools to check color contrast where they are available, or an online tool like WebAIM’s color contrast checker, which I used to calculate the color contrasts throughout this article.

Not all elements need to have the same focus style. I personally try to keep focus indicators visually consistent as much as possible. But there are times when some elements could benefit from a different focus style, whether for aesthetic or usability purposes—or maybe even both! Get creative, but do so within the boundaries of accessibility. Creating nice focus indicators is a nice touch that not only shows your attention to detail, but it also shows that you care about all of your user’s experiences enough to spend a bit of time fine-tuning these details.


If you’re a designer, make a habit to design and include focus indicator styles in your design specs if you don’t already do so.

If you’re a developer, include focus styles in your CSS defaults. If you’re working with designers, strike up a discussion about focus styles with them if they don’t already prioritize them in design specs.

Sometimes, you don’t need permission, extra time, or extra budget to improve the accessibility and usability of your product. Focus indicators are one small yet critical addition to your product that has tremendous usability benefits. Spending a few extra minutes designing and adding them will pay dividends and improve your product for millions of people who will use it.

Resources, references and further reading


Find similar articles under: #accessibility   #CSS