Use anchors with react-router Use anchors with react-router javascript javascript

Use anchors with react-router


React Router Hash Link worked for me and is easy to install and implement:

$ npm install --save react-router-hash-link

In your component.js import it as Link:

import { HashLink as Link } from 'react-router-hash-link';

And instead of using an anchor <a>, use <Link> :

<Link to="home-page#section-three">Section three</Link>

Note: I used HashRouter instead of Router:


Here is one solution I have found (October 2016). It is is cross-browser compatible (tested in Internet Explorer, Firefox, Chrome, mobile Safari, and Safari).

You can provide an onUpdate property to your Router. This is called any time a route updates. This solution uses the onUpdate property to check if there is a DOM element that matches the hash, and then scrolls to it after the route transition is complete.

You must be using browserHistory and not hashHistory.

The answer is by "Rafrax" in Hash links #394.

Add this code to the place where you define <Router>:

import React from 'react';import { render } from 'react-dom';import { Router, Route, browserHistory } from 'react-router';const routes = (  // your routes);function hashLinkScroll() {  const { hash } = window.location;  if (hash !== '') {    // Push onto callback queue so it runs after the DOM is updated,    // this is required when navigating from a different page so that    // the element is rendered on the page before trying to getElementById.    setTimeout(() => {      const id = hash.replace('#', '');      const element = document.getElementById(id);      if (element) element.scrollIntoView();    }, 0);  }}render(  <Router    history={browserHistory}    routes={routes}    onUpdate={hashLinkScroll}  />,  document.getElementById('root'))

If you are feeling lazy and don't want to copy that code, you can use Anchorate which just defines that function for you. https://github.com/adjohnson916/anchorate


Here's a simple solution that doesn't require any subscriptions nor third-party packages. It should work with react-router@3 and above and react-router-dom.

Working example: https://fglet.codesandbox.io/

Source (unfortunately, it doesn't currently work within the editor):

Edit Simple React Anchor


#ScrollHandler Hook Example

import { useEffect } from "react";import PropTypes from "prop-types";import { withRouter } from "react-router-dom";const ScrollHandler = ({ location, children }) => {  useEffect(    () => {      const element = document.getElementById(location.hash.replace("#", ""));      setTimeout(() => {        window.scrollTo({          behavior: element ? "smooth" : "auto",          top: element ? element.offsetTop : 0        });      }, 100);    }, [location]);  );  return children;};ScrollHandler.propTypes = {  children: PropTypes.node.isRequired,  location: PropTypes.shape({    hash: PropTypes.string,  }).isRequired};export default withRouter(ScrollHandler);

#ScrollHandler Class Example

import { PureComponent } from "react";import PropTypes from "prop-types";import { withRouter } from "react-router-dom";class ScrollHandler extends PureComponent {  componentDidMount = () => this.handleScroll();  componentDidUpdate = prevProps => {    const { location: { pathname, hash } } = this.props;    if (      pathname !== prevProps.location.pathname ||      hash !== prevProps.location.hash    ) {      this.handleScroll();    }  };  handleScroll = () => {    const { location: { hash } } = this.props;    const element = document.getElementById(hash.replace("#", ""));    setTimeout(() => {      window.scrollTo({        behavior: element ? "smooth" : "auto",        top: element ? element.offsetTop : 0      });    }, 100);  };  render = () => this.props.children;};ScrollHandler.propTypes = {  children: PropTypes.node.isRequired,  location: PropTypes.shape({    hash: PropTypes.string,    pathname: PropTypes.string,  })};export default withRouter(ScrollHandler);