Skip to content

Instantly share code, notes, and snippets.

@ryanditjia
Last active September 27, 2021 12:36
Show Gist options
  • Save ryanditjia/f66dd1d0e7dfd678a18dc4a15de8531d to your computer and use it in GitHub Desktop.
Save ryanditjia/f66dd1d0e7dfd678a18dc4a15de8531d to your computer and use it in GitHub Desktop.
Gatsby smooth anchor scroll + history “bug” fix
import { PureComponent } from 'react'
// npm install smoothscroll-polyfill
// this is a polyfill for Safari
import smoothscroll from 'smoothscroll-polyfill'
import { performScroll, scrollToHref } from './helpers'
const handleHashChange = () => {
if (window.location.hash) {
scrollToHref(window.location.hash)
} else {
/* hash doesn’t exist, meaning it just got removed. scroll to the very top */
performScroll(0)
}
}
export default class HashChangeHandler extends PureComponent {
componentDidMount = () => {
smoothscroll.polyfill()
window.onhashchange = handleHashChange
}
render() {
return null
}
}
export const performScroll = (top) => {
/* invoke scroll, with behavior smooth (not supported in Safari as of writing) */
window.scrollTo({
behavior: 'smooth',
top,
})
}
export const scrollToHref = (href) => {
/* destination element to scroll to */
const destinationElement = document.querySelector(href)
performScroll(destinationElement.offsetTop)
}
import React from 'react'
import HashChangeHandler from './HashChangeHandler'
const Layout = ({ children }) => (
<div>
<header>Header</header>
<nav>Nav</nav>
{children}
<footer></footer>
<HashChangeHandler />
</div>
)
// if you’re using Gatsby v1, change children to be a function, as such: children()
export default Layout
@ryanditjia
Copy link
Author

Thank you for your feedback! props.history is working, but hash is required:

Warning: Failed prop type: The prop history.hash is marked as required in AnchorLink, but its value is undefined.

I could remove isRequired, but I think you required it not just for fun hehe (Line 70)

This was a mistake on my part, hash should be nested inside location, gist updated!

And is it possible to open an other page and scroll to a specific anchor? For example in a slider on the homepage with a link to a subpage. (from / to /subpage/#anchor). I tried it in such a setup and get an error in line #6.

SyntaxError: Failed to execute 'querySelector' on 'Document': '/think-tank/#post-quantum-crypto' is not a valid selector.

Currently I try to fix it in IE11 & Edge. Chrome and Firefox is working fine... as usual ;-)

So this doesn’t work in IE11 and Edge? I have only tried Safari, Chrome, Firefox 😄.

Anyway, I have another component inside of Layout that lets the smooth scrolling work when clicking the browser back and forward buttons. I name it HashChangeHandler and I’ve pasted the code in this gist.

@cgpro
Copy link

cgpro commented Jun 26, 2018

Thank you for updating the gist! I've added a vanilla-smooth-scroll function... dont know why, scrollTo accepts only a number for x and y, but the behavior 'smooth' is totaly ignored... but it works for now in my case :)

@ryanditjia
Copy link
Author

I have modified the AnchorLink component to be closer to what I have on my site. If this confuses you, you can click Revisions to check the previous version! Hope this helps.

@eivindflobak
Copy link

eivindflobak commented Oct 7, 2018

This worked very well for me, thank you.

Now I have adjusted my site to fetch all its content from Markdown-files with GraphQL, and it's not working anymore. I put the anchor link destination in "h2" tags, like h2 id="1">Section Title< /h2>. Do you know why this could happen, and any workaround for this problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment