From 31066d4ebe2097c18f79bf8cba1222c07e9e9881 Mon Sep 17 00:00:00 2001 From: Ali Idrizi <20397725+ali-idrizi@users.noreply.github.com> Date: Fri, 3 Oct 2025 20:21:19 +0200 Subject: [PATCH 1/3] fix(useViewportSize): update size after hydration --- .../@react-aria/utils/src/useViewportSize.ts | 1 + .../utils/test/useViewportSize.ssr.test.tsx | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/@react-aria/utils/src/useViewportSize.ts b/packages/@react-aria/utils/src/useViewportSize.ts index 30fc9d26385..e40af6efd51 100644 --- a/packages/@react-aria/utils/src/useViewportSize.ts +++ b/packages/@react-aria/utils/src/useViewportSize.ts @@ -68,6 +68,7 @@ export function useViewportSize(): ViewportSize { window.addEventListener('blur', onBlur, true); + onResize(); if (!visualViewport) { window.addEventListener('resize', onResize); } else { diff --git a/packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx b/packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx index a5dcf31ae6c..37b20864174 100644 --- a/packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx +++ b/packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx @@ -10,7 +10,7 @@ * governing permissions and limitations under the License. */ -import {testSSR} from '@react-spectrum/test-utils-internal'; +import {testSSR, screen} from '@react-spectrum/test-utils-internal'; describe('useViewportSize SSR', () => { it('should render without errors', async () => { @@ -25,4 +25,21 @@ describe('useViewportSize SSR', () => { `); }); + + it('should update dimensions after hydration', async () => { + await testSSR(__filename, ` + import {useViewportSize} from '../src'; + + function Viewport() { + let size = useViewportSize(); + return
{size.width}x{size.height}
; + } + + + `, () => { + expect(screen.getByTestId('viewport')).toHaveTextContent('0x0'); + }); + + expect(screen.getByTestId('viewport')).not.toHaveTextContent('0x0'); + }); }); From 24d1eb41485c74b7318dbd06a66a7e5110479637 Mon Sep 17 00:00:00 2001 From: Ali Idrizi <20397725+ali-idrizi@users.noreply.github.com> Date: Fri, 3 Oct 2025 20:44:33 +0200 Subject: [PATCH 2/3] fix import order --- packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx b/packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx index 37b20864174..e14deb7b3bc 100644 --- a/packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx +++ b/packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx @@ -10,7 +10,7 @@ * governing permissions and limitations under the License. */ -import {testSSR, screen} from '@react-spectrum/test-utils-internal'; +import {screen, testSSR} from '@react-spectrum/test-utils-internal'; describe('useViewportSize SSR', () => { it('should render without errors', async () => { From c49afc2ac9fe0fffca5d409c99ff6c4fc94d5ab6 Mon Sep 17 00:00:00 2001 From: Ali Idrizi <20397725+ali-idrizi@users.noreply.github.com> Date: Sat, 4 Oct 2025 11:57:47 +0200 Subject: [PATCH 3/3] fix(useViewportSize): update size within the useEffect unconditionally --- .../@react-aria/utils/src/useViewportSize.ts | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/@react-aria/utils/src/useViewportSize.ts b/packages/@react-aria/utils/src/useViewportSize.ts index e40af6efd51..ed6f6f765e5 100644 --- a/packages/@react-aria/utils/src/useViewportSize.ts +++ b/packages/@react-aria/utils/src/useViewportSize.ts @@ -26,6 +26,15 @@ export function useViewportSize(): ViewportSize { let [size, setSize] = useState(() => isSSR ? {width: 0, height: 0} : getViewportSize()); useEffect(() => { + let updateSize = (newSize: ViewportSize) => { + setSize(size => { + if (newSize.width === size.width && newSize.height === size.height) { + return size; + } + return newSize; + }); + }; + // Use visualViewport api to track available height even on iOS virtual keyboard opening let onResize = () => { // Ignore updates when zoomed. @@ -33,13 +42,7 @@ export function useViewportSize(): ViewportSize { return; } - setSize(size => { - let newSize = getViewportSize(); - if (newSize.width === size.width && newSize.height === size.height) { - return size; - } - return newSize; - }); + updateSize(getViewportSize()); }; // When closing the keyboard, iOS does not fire the visual viewport resize event until the animation is complete. @@ -54,21 +57,16 @@ export function useViewportSize(): ViewportSize { // Wait one frame to see if a new element gets focused. frame = requestAnimationFrame(() => { if (!document.activeElement || !willOpenKeyboard(document.activeElement)) { - setSize(size => { - let newSize = {width: window.innerWidth, height: window.innerHeight}; - if (newSize.width === size.width && newSize.height === size.height) { - return size; - } - return newSize; - }); + updateSize({width: window.innerWidth, height: window.innerHeight}); } }); } }; + updateSize(getViewportSize()); + window.addEventListener('blur', onBlur, true); - onResize(); if (!visualViewport) { window.addEventListener('resize', onResize); } else {