Skip to content

fix: link doesn't scroll to section anchor again (#88986)#89459

Open
kairosci wants to merge 4 commits intovercel:canaryfrom
kairosci:fix-link-anchor-scroll
Open

fix: link doesn't scroll to section anchor again (#88986)#89459
kairosci wants to merge 4 commits intovercel:canaryfrom
kairosci:fix-link-anchor-scroll

Conversation

@kairosci
Copy link

@kairosci kairosci commented Feb 3, 2026

Description

Fixes an issue where clicking a link with a hash fragment would not scroll to the target element if clicked multiple times.

Problem

When a user clicks a link with a hash (e.g., <Link href="#section" />) and then scrolls manually away from the target, clicking the same link again would not scroll back to the section. This is because focusAndScrollRef.apply was set to false after the first scroll and was never reset for subsequent navigations to the same hash.

Solution

Modified packages/next/src/client/components/segment-cache/navigation.ts in the completeSoftNavigation function to ensure that when a hash fragment is present in the navigation, the scroll behavior is always applied.

Note: The original fix targeted handle-mutable.ts, but that file was removed in upstream refactor #88046 (commit 8fe154f). The logic was consolidated into the new navigation system. This PR applies the same fix to the current codebase at the correct location.

The fix ensures that when navigating to a URL with a hash fragment (url.hash !== ''), the focusAndScrollRef.apply flag is set to true even if other route segments haven't changed. This handles both cases:

  • Clicking different hash links on the same page
  • Clicking the same hash link multiple times (e.g., after manual scroll)

Changed File

  • packages/next/src/client/components/segment-cache/navigation.ts - Updated the apply logic in focusAndScrollRef to check for hash fragments

Testing

  • Existing test: test/e2e/app-dir/navigation/navigation.test.ts (hash-link-back-to-same-page)

Related

Fixes #88986

Copy link
Contributor

@lukesandberg lukesandberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There appear to be two different changes commingled in this PR

the changes to the link logic and an improvement to the no-html-link-for-pages lint rule, it isn't immediately obvious how these are related.... can you update the PR description to address (or maybe split the lint change into a new PR)

@kairosci kairosci force-pushed the fix-link-anchor-scroll branch from 7209ed6 to 9311fc0 Compare February 4, 2026 00:21
@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Feb 4, 2026

Allow CI Workflow Run

  • approve CI run for commit: 05b7f1c

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

@kairosci kairosci force-pushed the fix-link-anchor-scroll branch from 9311fc0 to fefb4a9 Compare February 4, 2026 00:23
@kairosci kairosci requested a review from lukesandberg February 4, 2026 00:25
Fixes an issue where clicking a link with a hash fragment would not scroll to the target element if clicked multiple times.

The problem was that after the first scroll, focusAndScrollRef.apply was set to false and never reset for subsequent clicks to the same hash. This fix ensures that when a hash fragment is present in the navigation, the scroll behavior is always applied, allowing users to click the same hash link multiple times and scroll each time.

This handles both cases:
- Clicking different hash links on the same page
- Clicking the same hash link multiple times (e.g., after manual scroll)

Test: test/e2e/app-dir/navigation (hash-link-back-to-same-page)
@kairosci kairosci force-pushed the fix-link-anchor-scroll branch from fefb4a9 to cad25d2 Compare February 4, 2026 00:32
@kairosci
Copy link
Author

kairosci commented Feb 4, 2026

Split the changes (which shouldn't have been there in the first place), updated the codebase, readjusted the fix, added the test.

Everything should be OK now, @lukesandberg PTAL.

Copy link
Contributor

@lukesandberg lukesandberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I patched your PR and observed that the test you added passes without the change to natigation.ts

this matches the observation posted in #88986 (comment)

This appears to have been fixed by #88046 still the test case is useful and i would be happy to accept it

: oldState.focusAndScrollRef.apply
: // Also apply scroll if we have a hash fragment, even if the hash didn't change.
// This allows clicking the same hash link multiple times to scroll each time.
onlyHashChange || (shouldScroll && url.hash !== '')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldScroll is always true at this point

i think this is equivalent to

 shouldScroll
  ? segmentPathsToScrollTo !== null || onlyHashChange || url.hash !== ''
  : oldState.focusAndScrollRef.apply

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking back, it could be a consideration.

yes, my initial goal was to force scroll to true

@lukesandberg lukesandberg self-assigned this Feb 5, 2026
@kairosci
Copy link
Author

kairosci commented Feb 5, 2026

So, can I delete fix and remain only the test?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Link doesn't scroll to section anchor (by id) again

3 participants