-
Notifications
You must be signed in to change notification settings - Fork 645
Description
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:
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.
Lines 41 to 46 in 1030509
| const {containerRef: navRef} = useFocusZone({ | |
| containerRef: customContainerRef, | |
| bindKeys: FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd, | |
| focusOutBehavior: 'wrap', | |
| focusInStrategy: customStrategy | |
| }) |
