focus-order

The order in which the focus moves between elements when using a keyboard should be logical and predictable by users.

Who might be affected
Screen Reader
Keyboard
Switch Control

Description

The focus order refers to the order in which assistive technologies, such as a keyboard or universal switch, move between the interactive elements on the screen. The focus order is essential to allow assistive technology users to navigate and perform actions in a logical order. It is a best practice to ensure that the programmatic order of interactive elements on the screen matches their visual order.

Quick Fixes

Ensure that the programmatic order of interactive elements on screen is logical and predictable. In most cases the focus order should match the order of views, however if needed both platforms have attributes to manage the focus for assistive technologies, such as android:nextFocusForward, android:nextFocusUp (Android XML), and canBecomeFocused, focusGroupIdentifier. Note that these are referring to the focus order for an external keyboard and not the “accessibility focus” which affects the reading order of assistive technologies such as screen readers.

Android (.xml):

Default Order

To preserve the default focus order, do not set any 'nextFocus' attribute on any view on a screen. As a result, the focus will move in a natural order: from the top left view to the bottom right.

Overriding the default order

To override the default order, set to the one or more views one of the next focus attributes, depending on your needs:

(nextFocusLeft, nextFocusRight, nextFocusUp, nextFocusDown, nextFocusForward)

1 → 2 → 3

1<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 android:layout_width="match_parent"
3 android:layout_height="match_parent"
4 android:orientation="vertical"
5 android:padding="16dp">
6
7 <Button
8 android:id="@+id/button1"
9 android:text="Button 1"
10 android:layout_width="wrap_content"
11 android:layout_height="wrap_content"
12 android:nextFocusDown="@+id/button2"
13 android:layout_marginBottom="8dp" />
14
15 <Button
16 android:id="@+id/button2"
17 android:text="Button 2"
18 android:layout_width="wrap_content"
19 android:layout_height="wrap_content"
20 android:nextFocusDown="@+id/button3"
21 android:layout_marginBottom="8dp" />
22
23 <Button
24 android:id="@+id/button3"
25 android:text="Button 3"
26 android:layout_width="wrap_content"
27 android:layout_height="wrap_content"
28 android:nextFocusDown="@+id/button1" />
29
30</LinearLayout>

Android (Java):

1 // Set next focus directions for button1
2 button1.setNextFocusDownId(R.id.button2);
3 button1.setNextFocusUpId(R.id.button3);
4 button1.setNextFocusLeftId(R.id.button3);
5 button1.setNextFocusRightId(R.id.button2);
6 button1.setNextFocusForwardId(R.id.button2);
7
8 // Set next focus directions for button2
9 button2.setNextFocusDownId(R.id.button3);
10 button2.setNextFocusUpId(R.id.button1);
11 button2.setNextFocusLeftId(R.id.button1);
12 button2.setNextFocusRightId(R.id.button3);
13 button2.setNextFocusForwardId(R.id.button3);
14
15 // Set next focus directions for button3
16 button3.setNextFocusDownId(R.id.button1);
17 button3.setNextFocusUpId(R.id.button2);
18 button3.setNextFocusLeftId(R.id.button2);
19 button3.setNextFocusRightId(R.id.button1);
20 button3.setNextFocusForwardId(R.id.button1);

Android (Kotlin):

1 // Set next focus directions for button1
2 button1.nextFocusDownId = R.id.button2
3 button1.nextFocusUpId = R.id.button3
4 button1.nextFocusLeftId = R.id.button3
5 button1.nextFocusRightId = R.id.button2
6 button1.nextFocusForwardId = R.id.button2
7
8 // Set next focus directions for button2
9 button2.nextFocusDownId = R.id.button3
10 button2.nextFocusUpId = R.id.button1
11 button2.nextFocusLeftId = R.id.button1
12 button2.nextFocusRightId = R.id.button3
13 button2.nextFocusForwardId = R.id.button3
14
15 // Set next focus directions for button3
16 button3.nextFocusDownId = R.id.button1
17 button3.nextFocusUpId = R.id.button2
18 button3.nextFocusLeftId = R.id.button2
19 button3.nextFocusRightId = R.id.button1
20 button3.nextFocusForwardId = R.id.button1

Failing example

This is a particular case of a User Specified Order when the current view creates a loop, either by itself or through a chain of user-specified orders.

1 → 2 → 1

1<Button
2 android:id="@+id/button1"
3 android:text="Button 1"
4 android:layout_width="wrap_content"
5 android:layout_height="wrap_content"
6 android:nextFocusDown="@+id/button3"
7 android:layout_marginBottom="8dp" />
8
9 <Button
10 android:id="@+id/button2"
11 android:text="Button 2"
12 android:layout_width="wrap_content"
13 android:layout_height="wrap_content"
14 android:nextFocusDown="@+id/button1"
15 android:layout_marginBottom="8dp" />
16
17 <Button
18 android:id="@+id/button3"
19 android:text="Button 3"
20 android:layout_width="wrap_content"
21 android:nextFocusDown="@+id/button2"
22 android:layout_height="wrap_content" />

1 → 3 → 2

How Users Are Affected

Keyboard, magnifier, and screen reader users may become disoriented when tabbing, shifting the focus to unexpected spots on the screen, or if the programmatic order of the interactive elements does not make sense.

WCAG Success criteria

This issue might cause elements to fail one or more of the following Success criteria:
2.4.3 Focus Order (A)