Skip to content

fix: scroll to top on forward navigation into nested routes - #56

Merged
mkdir700 merged 1 commit into
mainfrom
fix/scroll-to-top-navigation
Jun 26, 2026
Merged

fix: scroll to top on forward navigation into nested routes#56
mkdir700 merged 1 commit into
mainfrom
fix/scroll-to-top-navigation

Conversation

@mkdir700

@mkdir700 mkdir700 commented Jun 26, 2026

Copy link
Copy Markdown
Member

Problem

Scrolling down a list page and clicking through to a detail page left the viewport parked partway down the new page — the user landed in the middle of an article instead of at its top.

Root cause

Next.js App Router only scrolls the changed route segment into view. Same-level navigations (e.g. //blog) scroll to the top fine, but descending into a nested segment that streams behind a loading.tsx Suspense boundary (e.g. /blog/blog/[slug], /compare/compare/[slug]) scrolls that inner segment into view — and re-anchors after the streamed content resolves — leaving the viewport mid-page (measured ~332–666px down).

Fix

Add a ScrollToTop client component in [locale]/layout.tsx that resets scroll to the top on forward navigation, while deliberately leaving alone:

  • the initial load (browser handles hash target / reload position)
  • back/forward navigations (native scroll restoration preserved — popstate is detected by an actual path change, so hash-only pops don't leave a stale flag)
  • in-page anchor (#hash) navigations

A requestAnimationFrame re-apply guards against Next re-scrolling once the suspended content resolves.

Being a client component in the layout, it does not opt any page into dynamic rendering.

Verification (Playwright + project checks)

Scenario Before After
list → detail (the bug) scrollY=666/332 0
detail → nav link 0 0 ✓
compare list → detail 0 ✓
home → subpage 0 0 ✓
browser back 332 332 (restoration respected, not forced to top) ✓
#faq anchor scrolls to section ✓
hash-pop → forward nav (edge) 0 ✓
  • bun run typecheck
  • bun run lint ✓ no warnings
  • bun run build ✓ all public [locale] pages remain Static/SSG/ISR (●), none turned Dynamic

Summary by CodeRabbit

  • New Features
    • Added automatic scroll-to-top behavior when navigating between pages, improving the browsing experience in the app.
    • Preserves the current scroll position for back/forward navigation and anchor links, so in-page navigation feels more natural.

Next.js App Router only scrolls the changed route segment into view, so
descending into a nested segment that streams behind a loading.tsx Suspense
boundary (e.g. /blog -> /blog/[slug]) left the viewport parked mid-page
instead of at the top of the new page.

Add a ScrollToTop client component in the locale layout that resets scroll
on forward navigation while preserving native back/forward restoration and
in-page anchor scrolling.
@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
uc-website Error Error Jun 26, 2026 3:06pm

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9ebf6b4f-bb25-4168-9f0b-bcfa34c13806

📥 Commits

Reviewing files that changed from the base of the PR and between 1bed865 and ad84969.

📒 Files selected for processing (2)
  • src/app/[locale]/layout.tsx
  • src/components/scroll-to-top.tsx

📝 Walkthrough

Walkthrough

Adds a client-side ScrollToTop component that resets window scroll on forward pathname changes while preserving initial loads, hash anchors, and back/forward navigation. The locale root layout now renders this component inside NextIntlClientProvider.

Changes

Scroll restoration

Layer / File(s) Summary
Scroll-to-top component
src/components/scroll-to-top.tsx
Introduces the client component, pathname and popstate tracking, and the scroll-to-top effects with hash and initial-load exclusions.
Locale layout wiring
src/app/[locale]/layout.tsx
Imports ScrollToTop and mounts it inside NextIntlClientProvider in the locale root layout.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 I hopped from page to page with glee,
and tucked my paws where scrolls should be.
Up to the top on fresh new trails,
but leave the anchors, links, and rails.
Hop-hop! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: fixing scroll-to-top behavior on forward navigation into nested routes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/scroll-to-top-navigation

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mkdir700
mkdir700 merged commit 8fcb4a5 into main Jun 26, 2026
4 of 5 checks passed
@mkdir700
mkdir700 deleted the fix/scroll-to-top-navigation branch June 26, 2026 15:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant