remix icon indicating copy to clipboard operation
remix copied to clipboard

ScrollRestoration requiring clicking links twice for <a> tags with href to a hash

Open brookslybrand opened this issue 1 year ago • 10 comments

What version of Remix are you using?

2.0.1

Are all your remix dependencies & dev-dependencies using the same version?

  • [X] Yes

Steps to Reproduce

I've created a reproduction in StackBlitz. I've only tested that this error happens in Chrome.

  • Click any of the links on the left hand side
  • Note: the first click will go to the appropriate hash if there is no hash already in the url
  • Subsequent clicks will not scroll the element with the appropriate id into view until clicked a second time

Here is a video reproduction of what is happening:

https://github.com/remix-run/remix/assets/12396812/045e00a7-d4b9-4803-8925-ce9f0ec37b10

A simple fix in the meantime is to replace <a> with <Link>

Expected Behavior

Clicking on an anchor tag with an href to a hash should scroll to the element with the appropriate id, regardless of the presence of ScrollRestoration

Actual Behavior

Basically, if you are using <a href='#hash-1'> with ScrollRestoration scroll gets hijacked and you have to click the link twice in order for the page to scroll to the element with the appropriate id.

brookslybrand avatar Oct 02 '23 15:10 brookslybrand

This was pointed out on Twitter

I'm going to replace the offending <a>'s with <Link>s to fix this in the meantime, but for historical purposes, here's a recording of the goofed docs

https://github.com/remix-run/remix/assets/12396812/0ecebc93-88e7-4eae-a281-72460993c2f7

brookslybrand avatar Oct 02 '23 15:10 brookslybrand

Hm, this is odd. I can dig into this as well since scroll-based hash linking should work out of the box

brophdawg11 avatar Oct 02 '23 17:10 brophdawg11

@brophdawg11 this is definitely an issue, I'm glad @brookslybrand stumbled upon this.

  1. I see this weird behavior with my toc at https://tailwind-remix-run-mdxjs-typescript-starter-blog.fly.dev/blog/features-in-v1
  2. Another example would be at https://tailwind-remix-run-mdxjs-typescript-starter-blog.fly.dev/blog/deriving-ols-estimator

For 2 above, select either 1 or 2 superscripts, that'll take you to the footnote and just like @brookslybrand you must double click to get it back to where you came from. And, after that any subsequent clicks require double clicks.

For 1 above, I see the double click issue but along with that if you click on a toc item then for the very first time it takes you to that item successfully and on clicking the back button, it takes you back to TOC but if you now select another item then it takes you to the previous item. I have noticed the "double click" issue here too but it is a bit random.

I was convinced I must be doing something wrong...

The source for this repo is at https://github.com/SangeetAgarwal/tailwind-remix-run-mdxjs-typescript-starter-blog

SangeetAgarwal avatar Oct 05 '23 15:10 SangeetAgarwal

I'm experiencing some weird issues with scrollRestoration myself. I'm using Link and NavLink components and I have links with URLs like /capabilities#markets. Most of the time, it works as expected, but occasionally it just takes me to the top of the page and the section that has the ID of "markets" is further down the page. I thought maybe this was due to lazy loading the markets section, but I don't think so. Also, navigating directly (typing it in the URL bar and hitting enter) to mydomain.com/capabilities#markets doesn't ever seem to work. It just goes to the top of the page. Something I literally just tried was adding a slash between the leaf segment and the anchor, like /capabilities/#markets and that seems to work. Now if I click a link with that href, it goes to the correct section on the page, but leaves the slash in there. If I navigate directly using the address bar, it takes the slash out but still goes to the correct section. ¯_(ツ)_/¯

jamestrenda avatar Oct 16 '23 18:10 jamestrenda

Im having this issue as well - and I can't update the anchor tags to <Links /> bc the markup Im working with is injected html. Is there any traction on getting this fixed?

shifraHolzer avatar Jan 02 '24 03:01 shifraHolzer

Not to be annoying, but are there any updates?

shifraHolzer avatar Mar 17 '24 02:03 shifraHolzer

Can you try injecting anchors with onclicks that e.preventDefault and scroll to the hash? Maybe that’ll work for now.

zackify avatar Mar 17 '24 02:03 zackify

I stumbled on the same problem and I've discovered that when I delete the popstate event - the links work on the 1st click.

You can even test it in the 1st post example

I hope that observation helps to fix it.

In my Remix app I'll do a slopy "hack" to kill the popstate event after page load for now

PS. remix 2.8.1

Ngorror avatar Mar 20 '24 08:03 Ngorror

Also, navigating directly (typing it in the URL bar and hitting enter) to mydomain.com/capabilities#markets doesn't ever seem to work. It just goes to the top of the page.

I have the same situation. I try to use <Link> and simple <a>, but have the same result - just scroll to top of the page

<a href="#leave-request">
  Leave request
</a>

...

<section id="leave-request">
  Form to send request
</section>

I use the following: "@remix-run/node": "^2.8.1", "@remix-run/react": "^2.8.1", "@remix-run/serve": "^2.8.1",

YuliyaMinsk avatar Mar 26 '24 15:03 YuliyaMinsk

Also, navigating directly (typing it in the URL bar and hitting enter) to mydomain.com/capabilities#markets doesn't ever seem to work. It just goes to the top of the page.

Did anyone find a good workaround for this? I'm having the same issue.

JacobNWolf avatar Apr 15 '24 18:04 JacobNWolf

hey folks - I finally got some time to dig into this and opened a PR with some information in https://github.com/remix-run/react-router/pull/11459. I think at the end of the day this is something RR should not try to solve for you for the reasons outlined in the linked PR.

I think the right solution is for apps to enhance these plain <a> links into React Router navigations using something like this delegated approach which you can just call in your root component with a ref for the <body> element. The logic in there currently handles all links but you could also alter it to only handle hash-change links too if that better fits your use case.

Do a couple folks want to give that approach a shot and see if it resolves your issues and we can close this out?

@brookslybrand It turns out the only reason these sidebar links weren't working as <a> tags on the Remix websote before was because the delegation wasn't wrapping the sidebar - only the markdown content div. Moving the ref up to the root div for that page also fixes it - but using <Link> is the better solution for links we're in control of so no need to change anything on our end.

brophdawg11 avatar Apr 16 '24 16:04 brophdawg11

also just to be clear - this is related specifically to the original issue of <a href="#hash"> links not working.

Also, navigating directly (typing it in the URL bar and hitting enter) to mydomain.com/capabilities#markets doesn't ever seem to work. It just goes to the top of the page

☝️ This is potentially a different issue entirely, so we should open a new issue with a reproduction for that to look into separately

brophdawg11 avatar Apr 16 '24 17:04 brophdawg11

@brookslybrand It turns out the only reason these sidebar links weren't working as tags on the Remix websote before was because the delegation wasn't wrapping the sidebar - only the markdown content div. Moving the ref up to the root div for that page also fixes it - but using <Link> is the better solution for links we're in control of so no need to change anything on our end.

Ahhh that makes sense. Yeah I wasn't super familiar with how our website works at the time. Thanks Matt for documenting all of this

brookslybrand avatar Apr 16 '24 17:04 brookslybrand

I'm going to close this out since the original issue is resolved by switching to <Link> or using the delegated event listener approach.

brophdawg11 avatar Apr 19 '24 14:04 brophdawg11