@@ -168,6 +168,7 @@ function App() {
168168 const filterToggleRef = useRef ( null ) ;
169169 const lastFocusedElementRef = useRef ( null ) ;
170170 const filterSidebarRef = useRef ( null ) ;
171+ const previousWidthRef = useRef ( window . innerWidth ) ;
171172
172173 // Tablist refs for comparison column selector (accessibility)
173174 const tabARef = useRef ( null ) ;
@@ -201,20 +202,26 @@ function App() {
201202 // Effect to handle responsive layout
202203 useEffect ( ( ) => {
203204 const handleResize = ( ) => {
204- const isNarrow = window . innerWidth < 1024 ; // lg breakpoint
205- const isMobileViewport = window . innerWidth < 768 ; // Mobile breakpoint
206- const isNarrowForComparisonViewport = window . innerWidth < 1280 ; // xl breakpoint - left sidebar can push
207- const isNarrowForTocViewport = window . innerWidth < 1600 ; // TOC needs more room (both sidebars + content)
205+ const currentWidth = window . innerWidth ;
206+ const widthChanged = currentWidth !== previousWidthRef . current ;
207+
208+ const isNarrow = currentWidth < 1024 ; // lg breakpoint
209+ const isMobileViewport = currentWidth < 768 ; // Mobile breakpoint
210+ const isNarrowForComparisonViewport = currentWidth < 1280 ; // xl breakpoint - left sidebar can push
211+ const isNarrowForTocViewport = currentWidth < 1600 ; // TOC needs more room (both sidebars + content)
208212 setIsSingleColumn ( isNarrow ) ;
209213 setIsMobile ( isMobileViewport ) ;
210214 setIsNarrowForComparison ( isNarrowForComparisonViewport ) ;
211215 setIsNarrowForToc ( isNarrowForTocViewport ) ;
212216
213- // Auto-collapse both sidebars on any resize while in mobile viewport
214- if ( isMobileViewport ) {
217+ // Auto-collapse both sidebars only when WIDTH changes in mobile viewport
218+ // This prevents keyboard appearing/disappearing from closing sidebars
219+ if ( isMobileViewport && widthChanged ) {
215220 setSidebarCollapsed ( true ) ;
216221 setTocCollapsed ( true ) ;
217222 }
223+
224+ previousWidthRef . current = currentWidth ;
218225 } ;
219226
220227 handleResize ( ) ; // Set initial state
@@ -352,8 +359,9 @@ function App() {
352359 } , [ hasOpenOverlay ] ) ;
353360
354361 // Move initial focus into opened sidebar for keyboard accessibility
362+ // Skip on mobile to prevent virtual keyboard from appearing
355363 useEffect ( ( ) => {
356- if ( hasOpenOverlay ) {
364+ if ( hasOpenOverlay && ! isMobile ) {
357365 // Focus first focusable element in the opened sidebar
358366 requestAnimationFrame ( ( ) => {
359367 if ( ! sidebarCollapsed && filterSidebarRef . current ) {
@@ -366,7 +374,7 @@ function App() {
366374 }
367375 } ) ;
368376 }
369- } , [ hasOpenOverlay , sidebarCollapsed , tocCollapsed ] ) ;
377+ } , [ hasOpenOverlay , sidebarCollapsed , tocCollapsed , isMobile ] ) ;
370378
371379 // Apply inert attribute to main content when overlay is open (focus trap)
372380 // Using useEffect for reliable attribute setting across all browsers
0 commit comments