From 603ec298511e1dd9314dd201ad8181d831a98632 Mon Sep 17 00:00:00 2001 From: BrianRid Date: Wed, 26 Jul 2023 10:47:39 +0200 Subject: [PATCH 1/2] feat: adding keyboard navigation to Tabs component for accessibility purpose --- src/Tabs.tsx | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/Tabs.tsx b/src/Tabs.tsx index 35600dec9..8c413b2f4 100644 --- a/src/Tabs.tsx +++ b/src/Tabs.tsx @@ -83,13 +83,14 @@ export const Tabs = memo( return index === -1 ? 0 : index; }; + const buttonRefs = React.useRef>([]); + const [selectedTabIndex, setSelectedTabIndex] = useState(getSelectedTabIndex); useEffect(() => { if (selectedTabId === undefined) { return; } - setSelectedTabIndex(getSelectedTabIndex()); }, [selectedTabId]); @@ -104,6 +105,45 @@ export const Tabs = memo( } }); + const onKeyboardNavigation = ( + event: React.KeyboardEvent | React.KeyboardEvent + ) => { + let targetIndex = selectedTabIndex; + switch (event.key) { + case "ArrowRight": + targetIndex = selectedTabIndex < tabs.length - 1 ? selectedTabIndex + 1 : 0; + break; + case "ArrowLeft": + targetIndex = selectedTabIndex === 0 ? tabs.length - 1 : selectedTabIndex - 1; + break; + case "Home": + targetIndex = 0; + break; + case "End": + targetIndex = tabs.length - 1; + break; + } + setSelectedTabIndex(targetIndex); + }; + + React.useEffect(() => { + const targetTabButton = buttonRefs.current[selectedTabIndex]; + if (targetTabButton) { + targetTabButton.focus(); + } + }, [selectedTabIndex]); + + React.useEffect(() => { + if (selectedTabId === undefined) { + onTabChange?.({ + tabIndex: selectedTabIndex, + "tab": tabs[selectedTabIndex] + }); + } else { + onTabChange(tabs[selectedTabIndex].tabId); + } + }, [selectedTabIndex]); + const { getPanelId, getTabId } = (function useClosure() { const id = useId(); @@ -124,10 +164,16 @@ export const Tabs = memo( style={style} {...rest} > -
    +
      onKeyboardNavigation(e)} + > {tabs.map(({ label, iconId }, tabIndex) => (