@@ -180,16 +180,18 @@ function TabList({
180180 exceptionallySetClassName,
181181 ...props
182182} : TabListProps ) : React . ReactElement | null {
183+ const tabListRef = React . useRef < HTMLDivElement | null > ( null )
184+ const tabListPrevWidthRef = React . useRef ( 0 )
185+
183186 const tabContextValue = React . useContext ( TabsContext )
184187
185188 const [ selectedTabElement , setSelectedTabElement ] = React . useState < HTMLElement | null > ( null )
186189 const [ selectedTabStyle , setSelectedTabStyle ] = React . useState < React . CSSProperties > ( { } )
187- const tabListRef = React . useRef < HTMLDivElement > ( null )
188190
189191 const selectedId = tabContextValue ?. tabStore . useState ( 'selectedId' )
190192
191- React . useLayoutEffect ( ( ) => {
192- function updateSelectedTabStyle ( ) {
193+ const updateSelectedTabPosition = React . useCallback (
194+ function updateSelectedTabPositionCallback ( ) {
193195 if ( ! selectedId || ! tabListRef . current ) {
194196 return
195197 }
@@ -207,16 +209,53 @@ function TabList({
207209 width : `${ selectedTab . offsetWidth } px` ,
208210 } )
209211 }
210- }
212+ } ,
213+ [ selectedId ] ,
214+ )
215+
216+ React . useEffect (
217+ function updateSelectedTabPositionOnTabChange ( ) {
218+ updateSelectedTabPosition ( )
219+ } ,
220+ // `selectedId` is a dependency to ensure the effect runs when the selected tab changes
221+ [ selectedId , updateSelectedTabPosition ] ,
222+ )
223+
224+ React . useEffect (
225+ function observeTabListWidthChange ( ) {
226+ let animationFrameId : number | null = null
227+
228+ const tabListObserver = new ResizeObserver ( ( [ entry ] ) => {
229+ const width = entry ?. contentRect . width
211230
212- updateSelectedTabStyle ( )
231+ if ( width && tabListPrevWidthRef . current !== width ) {
232+ tabListPrevWidthRef . current = width
213233
214- window . addEventListener ( 'resize' , updateSelectedTabStyle )
234+ if ( animationFrameId !== null ) {
235+ cancelAnimationFrame ( animationFrameId )
236+ }
215237
216- return function cleanupEventListener ( ) {
217- window . removeEventListener ( 'resize' , updateSelectedTabStyle )
218- }
219- } , [ selectedId ] )
238+ animationFrameId = requestAnimationFrame ( ( ) => {
239+ updateSelectedTabPosition ( )
240+ animationFrameId = null
241+ } )
242+ }
243+ } )
244+
245+ if ( tabListRef . current ) {
246+ tabListObserver . observe ( tabListRef . current )
247+ }
248+
249+ return function cleanupResizeObserver ( ) {
250+ if ( animationFrameId ) {
251+ cancelAnimationFrame ( animationFrameId )
252+ }
253+
254+ tabListObserver . disconnect ( )
255+ }
256+ } ,
257+ [ updateSelectedTabPosition ] ,
258+ )
220259
221260 if ( ! tabContextValue ) {
222261 return null
0 commit comments