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:
- Include it in a new Recipes section of the readme (got a few things in mind we could include there)
- 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])