import { useEffect, useRef } from "react"; import { useLocation } from "react-router-dom"; /** * `Layout`'s `
` carries `overflow-auto`, but its ancestor chain uses * `min-h-screen` rather than a hard `h-screen`, so on a page taller than the * viewport `
` just grows to fit its content instead of clipping it — * the window/document scrolls, not that element. Reset both: whichever one * actually owns the scroll on a given page, the other is a no-op. */ const SCROLL_CONTAINER_ID = "scroll-container"; /** First path segment, e.g. "/transactions/abc123" -> "transactions". */ function section(pathname: string): string { return pathname.split("/")[1] ?? ""; } /** * Resets scroll to the top when navigating to a different section of the * app (e.g. Budgets -> Reports), which plain `` never does on * its own — leaving a page scrolled mid-way exactly where you left it the * next time you open it, even after visiting somewhere else entirely. * * Deliberately keyed on the URL's first path segment rather than the whole * location: navigating within the same section — a query-string filter * (`/transactions?category=X`) or a path param for a detail view * (`/transactions/:id`) — is "the same page" with more state, not a new one, * and should keep the list scrolled where the user was reading it. */ export function ScrollToTop() { const { pathname } = useLocation(); const prevSection = useRef(null); useEffect(() => { const current = section(pathname); if (prevSection.current !== null && prevSection.current !== current) { window.scrollTo(0, 0); document.getElementById(SCROLL_CONTAINER_ID)?.scrollTo(0, 0); } prevSection.current = current; }, [pathname]); return null; }