Skip to content

Commit ea44126

Browse files
committed
fix: prevent mobile sidebars from closing when virtual keyboard appears
Track window width changes separately from height changes to distinguish between intentional viewport resizes (device rotation) and virtual keyboard appearance. Also skip auto-focus on mobile to prevent unwanted keyboard popups when opening sidebars.
1 parent 4514010 commit ea44126

1 file changed

Lines changed: 16 additions & 8 deletions

File tree

src/App.jsx

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)