From b2d6da7dfb10bb2582ee5c17e12f2f987a2574a2 Mon Sep 17 00:00:00 2001 From: jinhojang6 Date: Thu, 30 Apr 2026 15:40:09 +0900 Subject: [PATCH] feat: enhance ScrollToTop component with detailed documentation and scroll restoration logic --- apps/web/components/scroll-to-top.tsx | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/apps/web/components/scroll-to-top.tsx b/apps/web/components/scroll-to-top.tsx index 80ff7403f9..78d4aff492 100644 --- a/apps/web/components/scroll-to-top.tsx +++ b/apps/web/components/scroll-to-top.tsx @@ -4,6 +4,19 @@ import { useEffect } from 'react' import { usePathname } from '@/i18n/navigation' +/** + * Force every navigation — including browser back/forward and bfcache + * restore — to start at the top of the page. + * + * Why all three handlers are needed: + * - The pathname effect covers normal forward navigation. + * - `scrollRestoration = 'manual'` stops the browser from rewinding to + * the previous scroll position after React renders on back/forward. + * - `popstate` covers the back/forward case where the pathname effect + * would otherwise lose a race against the browser's restore. + * - `pageshow` with `event.persisted === true` covers bfcache restore, + * during which React effects do not re-run. + */ export default function ScrollToTop() { const pathname = usePathname() @@ -11,5 +24,27 @@ export default function ScrollToTop() { window.scrollTo({ top: 0, left: 0, behavior: 'instant' }) }, [pathname]) + useEffect(() => { + if ('scrollRestoration' in window.history) { + window.history.scrollRestoration = 'manual' + } + + const scrollToTop = () => { + window.scrollTo({ top: 0, left: 0, behavior: 'instant' }) + } + + const handlePageShow = (event: PageTransitionEvent) => { + if (event.persisted) scrollToTop() + } + + window.addEventListener('popstate', scrollToTop) + window.addEventListener('pageshow', handlePageShow) + + return () => { + window.removeEventListener('popstate', scrollToTop) + window.removeEventListener('pageshow', handlePageShow) + } + }, []) + return null }