Skip to content

Click-to-focus doesn't work with directional navigation #25596

Description

@viridia

The acquire_focus_tab_index observer which is installed by PointerFocusPlugin in bevy_input_focus only works with TabIndex, not other kinds of focusable entities. This means that when you click on a widget that uses directional navigation, it immediately loses focus; worse, the focus is set to None, so you can't get back to it by navigating, since the directional system doesn't know where to start.

The problem is that TabIndex was originally modeled after the HTML tab-index attribute, which has two different jobs: it indicates where the element should be in the tab order, but it also indicates that the element is focusable at all. Unfortunately, Bevy has two different focus navigation systems, and only one of them uses TabIndex.

Worse, there's no single component in the directional nav framework that indicates "this widget is focusable" - we have AutoDirectionalNavigation and we have the directional navigation override, but both of these indicate where the focus moves to when leaving the widget, not whether the widget can accept focus. Also, AutoDirectionalNavigation is in bevy_ui, which means that it's at a higher layer than bevy_input_focus, which cannot depend on it.

The right answer, I think, is to split TabIndex into two separate components: Focusable, which for now means that an entity can accept focus, and TabIndex which now only specifies the tab order.

We can make Focusable a required component for both TabIndex and AutoDirectionalNavigation, avoiding the need to migrate all the examples. For the manual directional navigation examples we might need to add Focusable explicitly.

We can update the sequential navigator to consider an entity with only Focusable (no TabIndex) to have an implicit tab index of zero. The acquire focus observer would then only use Focusable. All of the bevy feathers widgets which use TabIndex::default() would migration to just using Focusable.

We can also think about adding Focusable to all the headless widgets; we couldn't do this before, because we didn't want to assume that the widgets were only meant to be used in a sequential navigation context, but Focusable can work with either navigation type.

Another benefit of this approach: we can make a widget temporarily non-focusable by removing the Focusable marker, without losing it's tab order, which we couldn't before.

@alice-i-cecile @kfc35 @ickshonpe @gagnus

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-UIGraphical user interfaces, styles, layouts, and widgetsC-BugAn unexpected or incorrect behaviorD-ModestA "normal" level of difficulty; suitable for simple features or challenging fixesM-Migration-GuideA breaking change to Bevy's public API that needs to be noted in a migration guideS-Ready-For-ImplementationThis issue is ready for an implementation PR. Go for it!X-UncontroversialThis work is generally agreed upon

    Type

    No type

    Projects

    • Status
      Needs SME Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions