Focus
Indicating and managing focus is integral to keyboard accessibility
- Version:
- 0.1.0
- Status:
- Published
Introduction
When discussing access to web content, we often use the term assistive technologies[1]: software and devices to help those with disabilities. However, assistive technologies, unlike adaptive technologies (such as hearing aids), do not just address disability. A screen reader is not just for blind and vision-impaired users; it can be called upon to address educational and productivity requirements as well.
It’s misleading to think that the term "keyboard users" only applies to disabled people. The keyboard, whether mechanical or virtual, is used by most anyone at some point during interaction. All people use keyboards; some depend on them more than others.
For many, including those with temporary injuries and long term ailments, operating a mouse (or 'pointer') is not easy. The keyboard is assistive in that it provides an alternative means of selecting and activating interactive content — one that does not require fine motor control.
Accordingly, WCAG2.1 has a number of success criteria that cover keyboard navigation access. Keyboard Accessible[2] is its own section, and is complemented by the Focus Order and Focus visible rules under Navigation[3].
The purpose of this guide is to collate the various keyboard accessibility considerations for BBC content.
Recommended markup
Only interactive elements should be focusable by keyboard. If an element does not do anything when pressed, clicked, or tapped, it should not appear in focus order: the succession of elements focusable by using the Tab key.
The HTML standard offers a handful of elements for interactive purposes, including links (<a>
), buttons (<button>
), and form controls. These are not only focusable by default, but each provide an implicit role. The role identifies the class of element non-visually. For example, a link is identified as "link" and a button as "button" in screen reader output upon focusing the element. Blind and vision-impaired screen reader users are typically keyboard users, since they cannot (easily) perceive the interface's topology in order to guide a mouse/pointer.
We recommend that only semantic HTML be used for interactive elements. Creating accessible interactive elements for non-semantic markup is verbose and less robust.
✕ JavaScript dependency
The following will be identified as a button, and focusable with the application of a tabindex
value of 0
[4]. However, it cannot be activated like a <button>
by keyboard unless a keyboard event listener (for Enter and/or Space key presses) is supplied by JavaScript.
<div class="button" role="button" tabindex="0">Press me</div>
✓ Built in behaviour
The <button>
element does not require an explicit ARIA role, and it is focusable by default. Click events are triggered by Enter and/or Space automatically.
<button class="button">Press me</button>
Focus order
Focus order is the order in which interactive elements receive focus. Interfaces become confusing for sighted keyboard users when the focus order is at odds with the visual layout. This is exacerbated by magnification: when a user is zoomed in and navigating by focus, the interface may take them in unexpected directions and to unexpected locations.
There are two main things that are likely to disrupt focus order:
Positive tabindex
values
By default, focus order follows source order: the order that the elements appear in the markup. But numbered tabindex
values override this. That is: an element with tabindex="1"
will be the first focusable element on the page regardless of the source order. Navigation by keyboard would likely mean passing over interactive content — content that would become focusable after the tabindex="1"
element has been unfocused. This is unlikely to be desirable.
Avoid positive tabindex
values.
Layout augmentation
On English language websites, flow content is laid out from top to bottom (the block flow direction) and inline content from left to right (the writing direction)[5]. However, this can be disrupted by an improper use of some CSS layout techniques.
For example, the first (in source order) of two flow elements could be floated right, and the second floated left. This effectively reverses their visual order. If either element is focusable, or contains focusable content, the focus order will contradict the reading order.
:first-child {
float: right;
}
:last-child {
float: left;
}
The order
property, available in Flexbox and Grid contexts, can reorder elements along either the horizontal or vertical axes.
.flex {
display: flex;
}
.flex > :first-child {
order: 2;
}
As detailed in Grids, order
should be avoided, especially where interactive content is involved.
Recommended layout
As the WCAG2.1 2.4.7 Focus Visible mandates: "any keyboard operable user interface has a mode of operation where the keyboard focus indicator is visible". Without visible indication, it's not easy to tell which element currently has focus, if any.
User agents provide focus styles by default, but these diverge considerably, and are not sufficient under many circumstances[6].
To normalize browser behaviour, and make focus styles more apparent, remove the default style and provide your own. Any CSS declaration can be applied to the :focus
state, but be mindful that focus styles are functional styles, and must be visible under all circumstances.
Be aware that in some browsers background images are eliminated when Windows High Contrast Mode is active, and changes to colour alone could fail WCAG2.1 1.4.1 Use of color[7], so ensure that you provide a reasonably thick outline
using a colour with adequate contrast against all the backgrounds on the page where it could be visible. One simple way to achieve this is to set the outline colour to share the text's color
. This should be safe since the contrast for the text will already differentiate it from its background. The CSS to implement that simply omits the color
property:
:focus {
outline: 2px solid;
}
You may find your mouse users are confused or distracted by the focus style appearing when the element is clicked (activation and focus happen simultaneously). With progressive enhancement, you can suppress focus styles for mouse users in browsers that support :focus-visible
.
:focus {
outline: 2px solid;
}
:focus:not(:focus-visible) {
outline: none;
}
The second declaration block is dropped in browsers not supporting :focus-visible
, meaning the first declaration remains intact and all keyboard users are provided focus styles.
Recommended behaviour
Your principle responsibility towards focus behaviour is not to disrupt standard browser behaviour for focus. Only interactive elements should typically receive focus, and in an expected and logical order. As already covered, you should therefore avoid positive tabindex
values, and visual arrangements that contradict source order. Users should be able to press Tab to focus the next interactive element, and Shift and Tab to focus the previous one.
In rare cases, programmatic focus (focus elicited on the user's behalf) is necessary. For example, Action dialogs must take focus upon being opened. If not, the keyboard user would not be able to easily locate and operate that dialog's controls. It's important components like dialogs have the correct semantic information (in this case: role="dialog"
and an associated label). This information provides context when the user's focus is moved, letting them know what has happened and where they are.
Sometimes, as outlined in Routing, it's beneficial to move focus to a non-interactive element, such as a heading. This is legitimate so long as the element is not made user-focusable. A tabindex
value of -1
allows the element to be focused using JavaScript's focus()
method without placing it in focus order. It's a technique whereby the user's focus position can be moved without creating confusion or obstruction.
For convenience, here is the code from Routing, describing how to focus a single-page application's view upon route change. By focusing the heading, its content is announced in screen reader software, identifying the newly loaded view to the screen reader user.
const mainHeading = document.querySelector('h1');
mainHeading.tabindex = -1;
mainHeading.focus();
In React, you would defer to the refs
API:
// Initialize <h1 ref={this.mainHeading} tabindex="-1">Brexitcast</h1>
this.mainHeading = React.createRef();
// Focus the ref's DOM node (accessible as `current`)
this.mainHeading.current.focus();
Keyboard traps
Under all circumstances, it should be possible to leave the web page, and the browser, via keyboard. Accordingly, WCAG2.1 2.1.2 No Keyboard Trap[8] mandates focus can be moved away from any focusable element.
Restricting focus to the inside of a dialog (and between the various dialog elements) is not recommended. This technique makes it difficult for users to focus and operate parts of the browser chrome outside viewport, such as the address bar.
Instead, as outlined in Action dialogs, all content outside of the dialog should receive the inert
property while the dialog is open. This property (and its polyfill[9]) removes content from both focus order and screen reader announcement. The dialog becomes the only focusable context by default and explicitly confining focus to the dialog by augmenting focus order is no longer necessary.
<div class="content" inert></div>
<div role="dialog" open>...</div>
Related research
This topic does not yet have any related research available.
Further reading, elsewhere on the Web
Assistive technology — Wikipedia, https://en.wikipedia.org/wiki/Assistive_technology ↩︎
WCAG2.1 2.1 KeyboardAccessible, https://www.w3.org/TR/WCAG21/#keyboard-accessible ↩︎
WCAG2.1 2.4 Navigable, https://www.w3.org/TR/WCAG21/#navigable ↩︎
Using the
tabindex
attribute — The Paciello Group, https://developer.paciellogroup.com/blog/2014/08/using-the-tabindex-attribute/ ↩︎writing-mode
— MDN, https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode ↩︎Avoid default browser focus styles — Adrian Roselli, http://adrianroselli.com/2017/02/avoid-default-browser-focus-styles.html ↩︎
WCAG2.1 1.4.1 Use of color, https://www.w3.org/TR/WCAG21/#use-of-color ↩︎
WCAG2.1 2.1.2 No Keyboard Trap, https://www.w3.org/TR/WCAG21/#no-keyboard-trap ↩︎
WICG
inert
(polyfill), https://github.com/WICG/inert ↩︎