Support use of ScrollRestoration that does not automatically scroll to hash elements for specific navigate
calls
#10038
Replies: 2 comments
-
I am very interested in having smooth scroll to hash elements. It would be great to just have a new prop on the I currently have this working by adding |
Beta Was this translation helpful? Give feedback.
-
I've been trying to implement (2) above for a little while today and found this discussion. Our use case is to:
It would be great to have a pattern available from react-router/remix to do this, I don't see a solution in the comments in #10034 (comment) I could use the browser history API directly: function Bookmark({ id, children }: { id: string; children: React.ReactNode }) {
return (
<a
id={`${id}`}
href={`#${id}`}
onClick={(event) => {
history.pushState({}, "", `#${id}`);
document
.getElementById(id)
?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
event.preventDefault();
}}
>
{children}
</a>
);
} This works but doesn't cause a rerender if anything is monitoring I could use function Bookmark({ id, children }: { id: string; children: React.ReactNode }) {
const navigate = useNavigate();
return (
<a
id={`${id}`}
href={`#${id}`}
onClick={(event) => {
navigate(
{
hash: id,
},
{ replace: true, preventScrollReset: true },
);
document
.getElementById(id)
?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
event.preventDefault();
}}
>
{children}
</a>
);
} ...but this causes the browser to scroll directly to the element mid animation. @brophdawg11 Perhaps a scrollIntoView configuration option could be added to NavigateOptions? navigate(
{
hash: id,
},
{ scrollIntoView: true },
); |
Beta Was this translation helpful? Give feedback.
-
As originally described in #10034, the
useScrollRestoration
always scrolls to the hash element (if found) when navigating to a route containing a hash. See here:react-router/packages/react-router-dom/index.tsx
Lines 1207 to 1214 in 6120207
This behavior is regardless of the
preventScrollReset
value. That means that it's currently impossible to useuseScrollRestoration
/<ScrollRestoration />
and control the scrolling behavior when usingnavigate
orLink
s that point to routes with hashes. Apps are forced to have the app immediately jump to the hash element with no workaround.A couple scenarios where you would not want to immediately jump to a hash:
Link
/navigate
route that includes a hash, but does want the URL to be updated. Tabbed interfaces are one example. This is essentially the same behavior as whatpreventScrollReset
provides when a hash is not present, in that scroll position is maintained when navigating to the new route (no automatic scroll to any location).ScrollRestoration
to immediately jump for us. (Or maybe you need transitions, etc.)One suggested workaround from the original PR #10034 (comment) is to use
<ScrollRestoration getKey>
. However, this is different in behavior than whatpreventScrollReset
provides for non-hash routes and is more limiting, sincepreventScrollReset
allows you to avoid changing the scroll position during specific navigation events added to the stack, rather than storing/restoring scroll position based on thelocation
alone. (ChanginggetKey
has consequences for revisiting pages, making it quite different frompreventScrollReset
.)As such, it seems useful for
react-router
to provide the automated scroll restoration like it does today (so position on a page is preserved when using back/forward, and goes to the top or a hash when you want it to), while still allowing users to "opt out" of scroll-to functionality for specificnavigate
calls to routes, even if the route contains a hash. I think having the automatic "scroll to hash" behavior only run whenpreventScrollReset !== true
is sufficient and intuitive to achieve this, since thatpreventScrollReset
option is currently ignored entirely when a hash is present, and it would give users the same level of control as it does for non-hash links. Also open to other alternative APIs to achieve this.Beta Was this translation helpful? Give feedback.
All reactions