Skip to content

TabNav should exclude buttons within tabs from the focus zone #2319

@iansan5653

Description

@iansan5653

TabNav creates an automatic focus zone where focusing from tab to tab is performed via the arrow keys. This makes sense and matches the behavior recommended in the corresponding ARIA authoring guide.

However, there do exist tabs that have buttons inside them. For example, a tab might have a "close" button or a "menu" button. An example of this use-case is Projects, where we have a menu button on the active tab:

Screenshot of the Projects view tab menu anchor button, focused.

The anchor button for this menu is getting picked up by TabNav's focus zone, so it is only focusable via arrow keys. Instead, it should be the next focusable element via Tab. (See https://github.com/github/memex/issues/11966)

Confirmation that that is the correct approach was provided by the accessibility team in this Slack message:

Buttons are not valid inside a tab list structure, so must be placed outside of it. A pattern I've recommended in the past is to manage focus order so that when the user tabs from the tab list, they land on the button related to the tab they just came from, rather than there being a bunch of buttons in the tab order that don't map to anything in the user's mental mapping of the page.

Because TabNav does not allow configuring the focus zone, the only way to implement this behavior right now is to move the button outside of the TabNav altogether and then absolutely position it back into the tab. This is a really cumbersome and hacky approach, and it would be much easier to just fix this in the source component.

I think the simplest approach here would be to add a focusableElementFilter to the focus zone that checks if the element has role="tab". This wouldn't filter out tabs within tabs but that seems like a terrible idea anyway.

react/src/TabNav.tsx

Lines 41 to 46 in 1030509

const {containerRef: navRef} = useFocusZone({
containerRef: customContainerRef,
bindKeys: FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd,
focusOutBehavior: 'wrap',
focusInStrategy: customStrategy
})

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions