Provide logical and visible focus indication

It’s important to enhance keyboard usability by making sure that focus logically moves through the controls on the page and that there is a clear visible indication of which control currently has focus.

  • Make sure that focus order is logical. Focus order usually matches code order, so do what you can to ensure that the desired focus order matches the visual layout of controls. Don’t use the tabindex attribute with any value greater than 0 in an effort to change focus order of a control. This can lead to unpredictable changes to focus order, such as if additional controls were to be later added to the page.
  • Provide a clear visual indication of focus. Use CSS to provide a clear visual indication of when links, buttons, and other active control receives focus, such as through a border line or change in text color or background color, or preferably a combination of those effects. The default browser focus effect is often not visually obvious enough, and sometimes those focus indications can be inadvertently suppressed when reset CSS files are used. For custom controls that aren’t natively focusable, such as divs or spans, use CSS to apply a visual focus effect because browsers will not provide any native indication.
  • Make hidden elements visible when they have focus. Watch out for visually hidden controls that are in the focus order. They can be confusing for sighted keyboard users: If a control isn’t supposed to be active, like a menu item in a dropdown menu that hasn’t been expanded, then it shouldn’t be able to receive focus. But if a control is hidden but available to receive focus, such as a “skip to main content” link, then it should become visible when it receives focus.

Testing

Use the Tab key to move through each active element on a page.

  • Is progress through elements logical, without unexpected jumps to different locations on the page?
  • Is there a clear visual indication for each element as it’s focused?

More information

✎ Technique: Focus order and tabindex

Interactive elements should, under most circumstances, be focusable in the order that they appear in the source code. This helps people who are using the keyboard or alternative input devices to follow focus in a logical order.

The order that elements appear in the document source should reflect the order they appear visually.

Examples

Bad example

The tabindex attribute can adjust the natural focus order of interactive elements like buttons and form inputs. For instance, tabindex="1" lets you make an element the first element focusable within a page, irrespective of where it appears in the source. However, this disrupts the page’s intuitive focus order. In the following example, the third button will receive focus first, then—because the first and second buttons have no positive tabindex value set—the first button will be focused next:


<button>first button</button> 
<button>second button</button>
<button tabindex="1">third button</button>

The only way to guarantee that an interactive element receives focus after the "third button" element would be to give it tabindex="2", and then give the next element tabindex="3", and so on, incrementing the tabindex value for each successive element. This can become unmaintainable very quickly, especially when the page is likely to accumulate new active elements over time.

Good example

For buttons, links and other interactive elements that are natively focusable, the best strategy is to avoid using the tabindex attribute altogether. In the following example, the first button is focused first and then after that, the third button is focused. The reason the second button is not in the focus order is because it is disabled (through the disabled attribute).


<button>first button</button> 
<button disabled>second button</button>
<button>third button</button>

Custom button example

The tabindex attribute is helpful for focus management in some cases, however. 

When making custom interactive elements (as one would when constructing a web component), they don't always automatically have traits like focusability built into them. You have to provide these manually. To make a custom element focusable like a <button> is, you must supply it with a tabindex value of 0:


<my-button role="button" tabindex="0">first button</my-button> 
<my-button role="button" tabindex="0">second button</my-button> 
<my-button role="button" tabindex="0">third button</my-button>

In the above code example, the custom <my-button> elements will be focused logically from first to third.

Disabling with tabindex="-1"

Custom elements do not support the disabled attribute, which would normally make them unfocusable (as in the second example). To simulate this behavior, you can give the element a tabindex value of -1.


<my-button role="button" tabindex="0">first button</my-button> 
<my-button role="button" tabindex="-1">second button</my-button> 
<my-button role="button" tabindex="0">third button</my-button>

In the above code example, the second button is not focusable. So focus moves directly from the first button to the third. To make sure that the simulated disabled styles for custom elements are in keeping with the disabled styles of standard buttons, you can use attribute selectors in your CSS:


button[disabled], [role="button"][tabindex="-1"] {
  opacity: 0.6; /* fade the element out, to reduce its visual affordance */
}

Code editor

Test the tabindex values in the preceding examples using this code editor. Be sure to experiment by changing and removing the tabindex attributes before and then use your TAB key to switch focus between the elements.

✎ Technique: Paragraph link focus indication

All interactive elements should be focusable so that they can be activated using a mouse, a keyboard, voice recognition software, a switch input device, and other input methods.

They should also indicate when they’re focused so that users know which element they are currently interacting with. This is where focus styles come into play.

Examples

Good example

All browsers support basic focus styles by default through their user-agent stylesheet. Browsers’ default focus styles vary from blue rings (Chrome) to dotted outlines (Firefox). To support basic focus styles, do not eliminate the user agent style unless you replace it with something else.

Bad example

To eliminate user agent focus styles in most browsers, you could supply the declaration outline: none. Do not do this unless you plan to provide a clear custom focus style in its place.


p a:focus {
  outline: none; /* this is not advised */
}

Improving visual focus indication

The default dotted focus outline provided by some browsers is not very clear, and it isn’t applied to custom controls that have been included in focus order. So you need to provide clear visual styling to show which control has focus.

You could add a border around the control (this might be especially effective for buttons) or change the color of text or change the background color (or a combination of those). Whichever method you choose, avoid introducing unexpected animated effects, which can occur if borders are applied inappropriately or if text size is changed.

In this example, which avoids those expected effects, CSS is used to change the background color of the paragraph text link when it receives focus, highlighting it as yellow:


p a:focus {
  outline: none; 
  background: #fea;
}

✎ Technique: Managing focus and inactive elements

Visually indicating which element has focus is important for effective keyboard navigation. It's also important to ensure that only those elements that are available visually for interaction are focusable. If an active element is intended to be unavailable in a particular state and it’s hidden from view, it should not be able to receive focus.

Having to tab through invisible controls to reach visible ones is arduous and potentially confusing for sighted users navigating the page by keyboard. Also, screen-reader users will hear the presence of controls that are intended to be hidden from use.

Examples

✓ Good example

In this example, an undisclosed submenu is hidden using display:none. Any children of elements with display:none are unfocusable, meaning that the invisible menu items are not in the focus order. This is correct.


<a href="#" aria-haspopup="true" role="button" aria-expanded="false">Good example</a>
<ul aria-label="submenu" style="display:none">
  <li><a href="#">News</a></li><!-- not focusable -->
  <li><a href="#">Contact Us</a></li>
</ul>

When the user clicks the aria-haspopup="true" link, JavaScript should reveal the submenu by setting its display value to block. This both reveals the menu visually and makes its items focusable.


<a href="#" aria-haspopup="true" role="button" aria-expanded="true">Good example</a>
<ul aria-label="submenu" style="display:block">
  <li><a href="#">News</a></li> <!-- focusable -->
  <li><a href="#">Contact Us</a></li>
</ul>

✗ Bad example

Another way to hide the submenu from view would be to set height:0 and overflow:hidden. The hidden submenu's items would still be in the focus order, meaning that a user who’s navigating using their keyboard would be able to focus controls that are not intended to be available.


<a href="#" aria-haspopup="true" role="button" aria-expanded="false">Bad example</a>
<ul aria-label="submenu" style="height:0;overflow:hidden">
  <li><a href="#">News</a></li> <!-- focusable -->
  <li><a href="#">Contact Us</a></li>
</ul>

✓ Good example

One exception to the rule of not including hidden controls in focus order is elements that become visible once they’re focused, like skip links. Skip links are navigation aids that provide a means for keyboard users to bypass navigation bars and jump directly to main page content, making it easier to get to important content.

In such a case, one implementation is to have these links hidden from view by default but still included in the page’s focus order. When they receive focus, the link text (for example "Skip to main content") should become visible so that keyboard users are made aware of the presence of the link and can choose to follow it if they wish.

Video: Invisible submenus and focus with NVDA and Firefox

Code editor

There is a code editor available to explore good and bad focus treatment relating to inactive controls. Try moving focus through the menu structure using your TAB key to see how the good and bad examples compare.