Change focus traversal order

The Default focus traversal order section described how Compose automatically adds focus traversal behavior to your elements, for both one-dimensional (tab key) and two-dimensional (arrow keys) navigation. In some cases, you might need to override this default behavior and be more explicit about the required traversal order.

Override one-dimensional traversal order

To change the default focus traversal order for one-dimensional navigation, you create a set of references, one for each focusable composable:

val (first, second, third, fourth) = remember { FocusRequester.createRefs() }

Then, use the focusRequester modifier to associate each of them with a composable:

Column {
    Row {
        TextButton({}, Modifier.focusRequester(first)) { Text("First field") }
        TextButton({}, Modifier.focusRequester(third)) { Text("Third field") }
    }

    Row {
        TextButton({}, Modifier.focusRequester(second)) { Text("Second field") }
        TextButton({}, Modifier.focusRequester(fourth)) { Text("Fourth field") }
    }
}

You can now use the focusProperties modifier to specify a custom traversal order:

Column {
    Row {
        TextButton(
            {},
            Modifier
                .focusRequester(first)
                .focusProperties { next = second }
        ) {
            Text("First field")
        }
        TextButton(
            {},
            Modifier
                .focusRequester(third)
                .focusProperties { next = fourth }
        ) {
            Text("Third field")
        }
    }

    Row {
        TextButton(
            {},
            Modifier
                .focusRequester(second)
                .focusProperties { next = third }
        ) {
            Text("Second field")
        }
        TextButton(
            {},
            Modifier
                .focusRequester(fourth)
                .focusProperties { next = first }
        ) {
            Text("Fourth field")
        }
    }
}

Override two-dimensional traversal order

It is also possible to add fine-grained control over the focus traversal order for two-dimensional navigation with the arrow keys. For each element, you can override the default navigation destination for each of the directions by adding the focusProperties modifier and specifying the item that would come up, down, or any other direction:

TextButton(
    onClick = {},
    modifier = Modifier
        .focusRequester(fourth)
        .focusProperties {
            down = third
            right = second
        }
) {}

This technique not only effectively uses keyboard arrows, but would work with D-Pads and sticks on wired and wireless controllers.

Jetpack Compose is Android's recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

Updated Mar 24, 2025

Jetpack Compose is Android's recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.

Updated Mar 24, 2025