Can't get tab navigation to work correctly with a controller in UI Toolkit

I am having difficulties getting a controller to work with UI Toolkit and the new InputSystem.

All of the controls have a tabIndex value set.

When I toggle with a keyboard using the tab key, the navigation works as expected. When I use the arrow keys to change a slider value, I get unpredictable results. It bounces between controls while updating the slider.

Using an Xbox controller is worse. I can’t repeat the tab navigation by moving the left stick. It moves to the control spatially on the form. In the actual game UI, there are some controls I can’t navigate to at all with a controller. Specifically the toggle, because with styling it’s lower than any of the buttons to the left.

I have a simple example project demonstrating this at GitHub - deege/SimpleTabTest: A Simple tab test to demonstrate problem in Unity UI Toolkit

What is the best practice for getting a controller navigation working with UI Toolkit, and with sliders?

If you haven’t already, make sure you understand how tabindex works in UI toolkit: Unity - Manual: Focus order of elements

But, my honest opinion, if you intend for your UI to be used primarily with a controller, if needs to be designed with a controller in mind first and foremost.

The way I solved this in my current project was to keep the number of navigable elements as small as possible at all times; such as only ever a list of buttons, or ListView to navigate through. Does mean you need to ensure certain elements that might be focusable aren’t focusable. Didn’t need to worry about custom navigation at that point.

Otherwise we do need better tools to customise navigation in UI Toolkit.

Thanks for the input. I do understand how tabIndex works. And tabIndex does work in my example and game. It falls apart when I try to use a controller.

There are two main problems:

  1. The controller ignores tabIndex and tries to move spatially. If UI controls are not directly east/west, the controller has difficulty navigating to them.

  2. When using a slider (with a controller or keyboard), it is interpreting the action as a movement AND changing the value. So it bounces between controls while updating values.

I feel rewriting control navigation for UI Toolkit seems overkill, because I’m probably doing something outside of how Unity wants me to use UI Toolkit. So I’m looking for how they want me to use it. I hope supporting a keyboard and controller for UI is not a niche case for UI Toolkit.

Tabindex is used when tabbing between elements, using a controller to change focus is not tabbing but direction-based navigation. When you press right, it looks to the right of the current element and finds the next one that can be selected, when you press up it scans up etc.
So the tabIndex will have no impact on any of this.
We made some improvements to this recently, especially with sliders. You can now press the submit button to toggle in/out of a slider so that you can still press left/right to change focus.
The changes landed in these versions:

  • 6.6f1
  • 2021.3.39f1
  • 2022.3.33f1
1 Like

Upgrading to current LTS solved most of the issues.

This I the actual UI I’m trying to work with. After updating to 2021.3.46f1 I can tab using the keyboard correctly through all the controls. Tab key works 100%.

The sliders can be manipulated with the left/right arrows. The up/down arrows will change focus between the sliders, but I cannot focus any other control using the arrows or the Xbox controller.

I can focus the mute toggle using the Xbox controller or arrow keys, if I’m moving the focus from the Language button. Moving focus from the Audio button using the controller or arrow keys goes no where. I can’t leave focus from the Audio button to any controls on the right. Moving the focus from Gameplay moves to Music.

Once I’m on a slider, I can only move to other sliders. Pressing the South button (A) has no effect on exiting a slider. Is there something I might have inadvertently set to to prevent the A button from working?

Edit: In the image the Sound FX is only highlighted because of :hover

Pressing the A button wont change the focus, it will however switch the mode so that if you then press left/right it should change focus instead of the slider value.

This is from the release notes:

UI Toolkit: Improved the navigation event handling logic for the slider.
When the slider detects move events aligned with the slider’s direction, it adjusts the slider’s value. If it detects a navigation submit event, it disables the movable class on the dragger element, causing all navigation events to revert to their default behavior. A second navigation submit event re-enables the class on the dragger and restores the previous customized behavior.

You can see an example of it in action here. When the Slider button color goes dark its changed mode. Ignore the labels (Not working properly etc)

166ccaaa-765d-4e3d-8455-23de281e7558

If you are using the default style sheet then you should also see the slider change color when the mode changes. If not you can add your own styles using the movable class to indicate the mode.

I updated the project in the first post to 2022.3.46f1

Running the program, the focus starts on the top left button.

  1. Move the Xbox controller left stick once to the right.
  2. Focus is now on the slider.
  3. Move the Xbox controller left stick once to the right. The slider value changes.
  4. Press A (South). There doesn’t seem to be a visible change using the default style.
  5. Move the Xbox controller left stick once to the left. Again the slider value changes, but does not change focus.

Is there something I’m missing here?

You mentioned to use the moveable class to indicate the mode. That class is in 6, but does not appear to be in 2022. Could this fix be in 6, but not in 2022.3.46f1?

Ok it does seem to be missing. I’m out of the office now but I’ll check Monday to see if it was missed.

Looks like I was mistaken. We backported some bug fixes but had to remove the slider changes as they were too big to backport and required some API that did not exist. So this is only available in Unity 6.

One thing you can do is to add some additional events or remap the current ones so that you can call Next and Previous instead, this will use the tabInddex where Next is the same as pressing tab and Previous is shift+tab.

If you move the Input system package into your projects Packages folder you can make changes to it.

The input system code you want is here InputSystem/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemProvider.cs at 7a28d7b061918032da928823917a932aa985189e · Unity-Technologies/InputSystem · GitHub

You would need to dispatch the same event but with NavigationEvent.Type.Next instead.

1 Like