breadadams / scroller-motion

🛹 Elegant motion scrolling for React

Home Page:https://scroller-motion.js.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Scroll to anchors not working

rijk opened this issue · comments

When clicking a link to an #id further down the page, nothing happens. When scroller-motion is disabled, the page jumps to the anchor, but when it is active, no scroll whatsoever. Probably because there is no React state change?

@rijk excuse the delay, I took a look last night and it seems the root cause of the issue is that the anchor's DOM position can't be read (because it's within the scroller-motion element - a position: fixed element).

I'll add this to the roadmap and address it asap, meanwhile you could use a custom solution of locating the offset of the anchored element and then using something like window.scrollTo.

Window scrolling events do work (as you can see in the demo, via the top-right "Scroll down" button).

Ahh, I wouldn't have thought of that 😄 Meanwhile, if you have some time could you help me out with #2 as well? I'd love to contribute to the package.

I used this workaround for now:

const onClick = ( e ) => {
  e.preventDefault()
  const anchor = e.target.getAttribute( 'href' ).substr( 1 )
  window.scrollTo( 0, document.getElementById( anchor ).offsetTop )
}

We can add something in the library to intercept hash changes. We can add a flag or something add this event listener to the component:

useEffect(() => {
  const listenHashChange = (e: HashChangeEvent) => {
    const {newURL} = e
    const [_, id] = newURL.match(/#(.*)$/)
    
    if (!id) {
      // scroll to top
      window.scrollTo(0, 0)
    }
    
    const el = document.getElementById(id)
    if (el) {
      // scroll to element
      window.scrollTo(0, el.offsetTop)
    }
  }
  window.addEventListener('hashchange', listenHashChange)
  
  return () => window.removeEventListener('hashchange', listenHashChange)
}, [])

I'm thinking that rather than including this in the "core" we either:

  1. Include it in a new Recipes section of the readme (got a few things in mind we could include there)
  2. Export a hook (i.e. useHashScroll) that users can choose to import/apply to their app, for tree-shaking benefits

Today I had a similar problem using Next 13 and that solution didn't work. However, it worked using router.events. Hope this can help someone:

  const router = useRouter()
  useEffect(() => {
    const onHashChangeStart = (url: string) => {
      const el = document.getElementById(url.slice(2))
      if (el) {
        window.scrollTo(0, el.offsetTop)
      }
    }
    router.events.on('hashChangeStart', onHashChangeStart)
    return () => {
      router.events.off('hashChangeStart', onHashChangeStart)
    }
  }, [router.events])