From e9bccc865ced643bdc1e262aa7efac16253dda94 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Fri, 12 Apr 2024 15:49:11 -0500 Subject: [PATCH] Tabs: Fallback to first enabled tab if no active tab Id (#60681) If there is no selectedTabId, focus will be placed on the tab container which requires an arrow keypress to move focus to the first tab. This behavior isn't as user friendly as focus should be placed on a tab. To prevent focus on the wrapper, if no element is focused and there is no activeId, fallback to the first enabled tab. Co-authored-by: Lena Morita --- packages/components/CHANGELOG.md | 4 +++ packages/components/src/tabs/index.tsx | 8 +++++ packages/components/src/tabs/test/index.tsx | 38 +++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 63ec961b80f3c..48827c815c585 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -15,6 +15,10 @@ - `ProgressBar`: Fix CSS variable with invalid value ([#60576](https://github.com/WordPress/gutenberg/pull/60576)). +### Experimental + +- `Tabs`: Fallback to first enabled tab if no active tab id ([#60681](https://github.com/WordPress/gutenberg/pull/60681)). + ## 27.3.0 (2024-04-03) ### Bug Fix diff --git a/packages/components/src/tabs/index.tsx b/packages/components/src/tabs/index.tsx index 5ffa8e97a651b..aaae3ed252750 100644 --- a/packages/components/src/tabs/index.tsx +++ b/packages/components/src/tabs/index.tsx @@ -153,6 +153,14 @@ function Tabs( { } }, [ isControlled, selectedTab, selectedTabId, setSelectedId ] ); + useEffect( () => { + // If there is no active tab, fallback to place focus on the first enabled tab + // so there is always an active element + if ( selectedTabId === null && ! activeId && firstEnabledTab?.id ) { + setActiveId( firstEnabledTab.id ); + } + }, [ selectedTabId, activeId, firstEnabledTab?.id, setActiveId ] ); + useEffect( () => { if ( ! isControlled ) { return; diff --git a/packages/components/src/tabs/test/index.tsx b/packages/components/src/tabs/test/index.tsx index 39c860de62c14..bbb7f591d0ffc 100644 --- a/packages/components/src/tabs/test/index.tsx +++ b/packages/components/src/tabs/test/index.tsx @@ -242,6 +242,44 @@ describe( 'Tabs', () => { await press.Tab(); expect( alphaButton ).toHaveFocus(); } ); + + it( 'should focus on the first enabled tab when pressing the Tab key if no tab is selected', async () => { + const TABS_WITH_ALPHA_DISABLED = TABS.map( ( tabObj ) => + tabObj.tabId === 'alpha' + ? { + ...tabObj, + tab: { + ...tabObj.tab, + disabled: true, + }, + } + : tabObj + ); + + render( + + ); + + await sleep(); + await press.Tab(); + expect( + await screen.findByRole( 'tab', { name: 'Beta' } ) + ).toHaveFocus(); + + await press.ArrowRight(); + expect( + await screen.findByRole( 'tab', { name: 'Gamma' } ) + ).toHaveFocus(); + + await press.Tab(); + await press.ShiftTab(); + expect( + await screen.findByRole( 'tab', { name: 'Gamma' } ) + ).toHaveFocus(); + } ); } ); describe( 'Tab Attributes', () => {