Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(react-router): implement hash change "Scroll Into View" option #2996

Merged

Conversation

joshuaslate
Copy link
Contributor

@joshuaslate joshuaslate commented Dec 12, 2024

I am working on an API documentation page that has a number of anchor links. The sidebar contains Link elements that expand/collapse sections based on if its hash is active. It works like a table of contents. I also update the hash based on the user's scroll position. If they've scrolled past an anchor, it updates the hash. The issue I was hitting is that updating the hash with navigate or a number of other methods actually runs scrollIntoView, which takes over the user's scrolling in these cases.

The change I'm proposing is to add an option to navigate and Link that will allow the consumer to choose to opt out of the default scrollIntoView behavior, or even allow them to customize the scroll behavior if they would like to (e.g., for smooth scrolling instead of instant).

Discussed in Discord here: https://discord.com/channels/719702312431386674/1316559407919796334

Another relevant discussion: #1155

@schiller-manuel schiller-manuel marked this pull request as ready for review December 13, 2024 01:33
@schiller-manuel
Copy link
Contributor

this looks great. let's wait for @SeanCassiere to review

Copy link
Contributor

@schiller-manuel schiller-manuel left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@SeanCassiere SeanCassiere left a comment

Choose a reason for hiding this comment

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

I'm not at home at the moment, so I'll have to check the sandbox locally at home tomorrow.

I'd also like us to think a bit more on the property name. The name hashChangeScrollIntoView just feels a bit off. Maybe even hashScrollIntoView?

Approving for now, but I'd like to get a chance to play with the sandbox before merging in.

packages/react-router/src/router.ts Show resolved Hide resolved
e2e/react-router/basic-file-based/src/routes/anchor.tsx Outdated Show resolved Hide resolved
@SeanCassiere SeanCassiere changed the title feat: implement hash change scrollIntoView option feat(react-router): implement hash change "Scroll Into View" option Dec 13, 2024
@joshuaslate
Copy link
Contributor Author

I believe I've addressed all of the feedback that's come in so far, please let me know if anything else comes up. I added the /anchor route to the basic-file-based example for easy manual testing in addition to the e2e tests.

@@ -1838,6 +1846,9 @@ export class Router<
}
}

nextHistory.state.__hashScrollIntoViewOptions =
hashScrollIntoView ?? this.options.defaultHashScrollIntoView ?? true
Copy link
Member

Choose a reason for hiding this comment

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

Would this (the ?? true) break any existing apps?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These options are new, so the value will default to true if they aren't provided.

I read on MDN for scrollIntoView that true is the default argument value, so passing true by default should maintain the behavior that exists today. I don't believe this is a breaking change.

I'm not at my computer right now, but I believe I added a test case and Link on the example that use the default behavior, and it seems to function the same as the released version does for me.

Copy link
Member

@SeanCassiere SeanCassiere left a comment

Choose a reason for hiding this comment

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

Tried out the sandbox and it looks good.

@schiller-manuel OK to merge from my side.

Copy link

nx-cloud bot commented Dec 14, 2024

☁️ Nx Cloud Report

CI is running/has finished running commands for commit 72339b6. As they complete they will appear below. Click to see the status, the terminal output, and the build insights.

📂 See all runs for this CI Pipeline Execution


✅ Successfully ran 1 target

Sent with 💌 from NxCloud.

Copy link

pkg-pr-new bot commented Dec 14, 2024

Open in Stackblitz

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/@tanstack/arktype-adapter@2996

@tanstack/create-router

npm i https://pkg.pr.new/@tanstack/create-router@2996

@tanstack/history

npm i https://pkg.pr.new/@tanstack/history@2996

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/@tanstack/eslint-plugin-router@2996

@tanstack/react-cross-context

npm i https://pkg.pr.new/@tanstack/react-cross-context@2996

@tanstack/react-router

npm i https://pkg.pr.new/@tanstack/react-router@2996

@tanstack/react-router-with-query

npm i https://pkg.pr.new/@tanstack/react-router-with-query@2996

@tanstack/router-cli

npm i https://pkg.pr.new/@tanstack/router-cli@2996

@tanstack/router-devtools

npm i https://pkg.pr.new/@tanstack/router-devtools@2996

@tanstack/router-generator

npm i https://pkg.pr.new/@tanstack/router-generator@2996

@tanstack/router-plugin

npm i https://pkg.pr.new/@tanstack/router-plugin@2996

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/@tanstack/router-vite-plugin@2996

@tanstack/start

npm i https://pkg.pr.new/@tanstack/start@2996

@tanstack/start-vite-plugin

npm i https://pkg.pr.new/@tanstack/start-vite-plugin@2996

@tanstack/valibot-adapter

npm i https://pkg.pr.new/@tanstack/valibot-adapter@2996

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/@tanstack/virtual-file-routes@2996

@tanstack/zod-adapter

npm i https://pkg.pr.new/@tanstack/zod-adapter@2996

commit: 72339b6

@joshuaslate
Copy link
Contributor Author

I was investigating the test failure from scroll restoration and found that if browser (not router)-controlled navigation happens, the router.state.location.state.__hashScrollIntoViewOptions option isn't being set, because it doesn't run through commitLocation.

I could add another nullish coalescing operator to set the value if it's undefined, like so:

if (typeof document !== 'undefined' && (document as any).querySelector) {
        const hashScrollIntoViewOptions =
          router.state.location.state.__hashScrollIntoViewOptions ?? true

        if (hashScrollIntoViewOptions && router.state.location.hash !== '') {
          const el = document.getElementById(router.state.location.hash)
          if (el) {
            el.scrollIntoView(hashScrollIntoViewOptions)
          }
        }
      }

This fixes the test and is working for me in the scroll restoration sandbox.

@SeanCassiere, does that sound ok to you?

@SeanCassiere
Copy link
Member

@SeanCassiere, does that sound ok to you?

Worth giving it a try.
I'll also be investigating what's going on here.

@SeanCassiere
Copy link
Member

cc @schiller-manuel

@schiller-manuel schiller-manuel merged commit 9214714 into TanStack:main Dec 14, 2024
5 checks passed
@joshuaslate joshuaslate deleted the feat-hash-change-scroll-behavior branch December 14, 2024 15:48
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.

3 participants