@@ -83,13 +83,14 @@ export const Tabs = memo(
8383 return index === - 1 ? 0 : index ;
8484 } ;
8585
86+ const buttonRefs = React . useRef < Array < HTMLButtonElement | null > > ( [ ] ) ;
87+
8688 const [ selectedTabIndex , setSelectedTabIndex ] = useState < number > ( getSelectedTabIndex ) ;
8789
8890 useEffect ( ( ) => {
8991 if ( selectedTabId === undefined ) {
9092 return ;
9193 }
92-
9394 setSelectedTabIndex ( getSelectedTabIndex ( ) ) ;
9495 } , [ selectedTabId ] ) ;
9596
@@ -104,6 +105,34 @@ export const Tabs = memo(
104105 }
105106 } ) ;
106107
108+ const onKeyboardNavigation = (
109+ event : React . KeyboardEvent < HTMLButtonElement > | React . KeyboardEvent < HTMLUListElement >
110+ ) => {
111+ let targetIndex = selectedTabIndex ;
112+ switch ( event . key ) {
113+ case "ArrowRight" :
114+ targetIndex = selectedTabIndex < tabs . length - 1 ? selectedTabIndex + 1 : 0 ;
115+ break ;
116+ case "ArrowLeft" :
117+ targetIndex = selectedTabIndex === 0 ? tabs . length - 1 : selectedTabIndex - 1 ;
118+ break ;
119+ case "Home" :
120+ targetIndex = 0 ;
121+ break ;
122+ case "End" :
123+ targetIndex = tabs . length - 1 ;
124+ break ;
125+ }
126+ buttonRefs . current [ targetIndex ] ?. click ( ) ;
127+ } ;
128+
129+ React . useEffect ( ( ) => {
130+ const targetTabButton = buttonRefs . current [ selectedTabIndex ] ;
131+ if ( targetTabButton ) {
132+ targetTabButton . focus ( ) ;
133+ }
134+ } , [ selectedTabIndex ] ) ;
135+
107136 const { getPanelId, getTabId } = ( function useClosure ( ) {
108137 const id = useId ( ) ;
109138
@@ -124,10 +153,16 @@ export const Tabs = memo(
124153 style = { style }
125154 { ...rest }
126155 >
127- < ul className = { fr . cx ( "fr-tabs__list" ) } role = "tablist" aria-label = { label } >
156+ < ul
157+ className = { fr . cx ( "fr-tabs__list" ) }
158+ role = "tablist"
159+ aria-label = { label }
160+ onKeyDownCapture = { e => onKeyboardNavigation ( e ) }
161+ >
128162 { tabs . map ( ( { label, iconId } , tabIndex ) => (
129163 < li key = { label + ( iconId ?? "" ) } role = "presentation" >
130164 < button
165+ ref = { button => ( buttonRefs . current [ tabIndex ] = button ) }
131166 id = { getTabId ( tabIndex ) }
132167 className = { cx (
133168 fr . cx ( "fr-tabs__tab" , iconId , "fr-tabs__tab--icon-left" ) ,
0 commit comments