-
-
Save ryanditjia/f66dd1d0e7dfd678a18dc4a15de8531d to your computer and use it in GitHub Desktop.
| import React from 'react' | |
| import { string, node, func, shape } from 'prop-types' | |
| import { scrollToHref } from './helpers' | |
| const handleClick = ({ href, callback, history, event }) => { | |
| /* prevent normal link behavior */ | |
| event.preventDefault() | |
| /* call the function */ | |
| scrollToHref(href) | |
| /* | |
| * only push to browser history if it’s a new anchor | |
| * | |
| * this fixes the “bug” in Gatsby (react-router ?) | |
| * where the same hash can be pushed to history | |
| * | |
| * if you want to stick to default Gatsby behavior, remove the if condition block | |
| * and uncomment history.push(href) following it | |
| */ | |
| if (history.location.hash !== href) { | |
| history.push(href) | |
| } | |
| /* Uncomment below line if you want default Gatsby behavior */ | |
| // history.push(href) | |
| /* perform callback (example: closing modal sidebar) */ | |
| if (callback) { | |
| callback() | |
| } | |
| } | |
| const AnchorLink = ({ href, history, callback, children, ...restProps }) => ( | |
| <a | |
| href={href} | |
| onClick={event => | |
| handleClick({ | |
| href, | |
| callback, // optional callback, I use it to close modal sidebar | |
| history, // history object props that layout and pages have | |
| event, | |
| }) | |
| } | |
| {...restProps} | |
| > | |
| {children} | |
| </a> | |
| ) | |
| AnchorLink.propTypes = { | |
| href: string.isRequired, | |
| callback: func, | |
| children: node.isRequired, | |
| history: shape({ | |
| push: func.isRequired, | |
| location: shape({ | |
| hash: string.isRequired, | |
| }).isRequired, | |
| }).isRequired, | |
| } | |
| AnchorLink.defaultProps = { | |
| callback: undefined, | |
| } | |
| export default AnchorLink |
| 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 |
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.
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 :)
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.
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?
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.
Currently I try to fix it in IE11 & Edge. Chrome and Firefox is working fine... as usual ;-)