DEV Community

Daniel Gruner
Daniel Gruner

Posted on

34

Scroll to anchor element with React Router V6 (hash links, anchor links)

Hi! With inspiration of Nick Coughlin, I developed a pretty simple solution for using hash links or anchor links with React Router V6. As Nick proposes, it's without any further dependency like the popular react-router-hash-links.

Target

Goal is that your app scrolls to a certain element with a certain ID, when a so called hash link or anchor link is used.

Example:

...
// react-router Link component
<Link to="/mypage#myheadline">Press Link to get to headline</Link>
...
Enter fullscreen mode Exit fullscreen mode

By clicking this link, the user expects to be navigated to "/mypage" and scrolled to the element with ID "myheadline"

...
// headline with ID "myheadline"
<h2 id="myheadline">My Headline</h2>
...
Enter fullscreen mode Exit fullscreen mode

ScrollToAnchor.tsx or jsx

Put this component anywhere within your router component. It simply listens for location changes and determines if there is a hash (or element ID) that your app should scroll to.

import { useEffect, useRef } from 'react';
import { useLocation } from 'react-router-dom';

function ScrollToAnchor() {
  const location = useLocation();
  const lastHash = useRef('');

  // listen to location change using useEffect with location as dependency
  // https://jasonwatmore.com/react-router-v6-listen-to-location-route-change-without-history-listen
  useEffect(() => {
    if (location.hash) {
      lastHash.current = location.hash.slice(1); // safe hash for further use after navigation
    }

    if (lastHash.current && document.getElementById(lastHash.current)) {
      setTimeout(() => {
        document
          .getElementById(lastHash.current)
          ?.scrollIntoView({ behavior: 'smooth', block: 'start' });
        lastHash.current = '';
      }, 100);
    }
  }, [location]);

  return null;
}

export default ScrollToAnchor;
Enter fullscreen mode Exit fullscreen mode

Heroku

Built for developers, by developers.

Whether you're building a simple prototype or a business-critical product, Heroku's fully-managed platform gives you the simplest path to delivering apps quickly — using the tools and languages you already love!

Learn More

Top comments (5)

Collapse
 
ncoughlin profile image
Nick Coughlin

This component has been converted to an NPM package with the following improvements:

  • no longer requires react-router as a dependency
  • typescript compatible

You can view the github repo here:
github > ncoughlin/scroll-to-hash-element

and the NPM repo here:
npm > scroll-to-hash-element

Collapse
 
davidd344 profile image
David Freitas • Edited

if you want scroll for after navbar, it's work for me:


import { useEffect, useRef } from 'react'
import { useLocation } from 'react-router-dom'

function ScrollToAnchor (): null {
  const location = useLocation()
  const lastHash = useRef('')
  const navbarHeight = 110
  console.log(location, lastHash)
  useEffect(() => {
    if (location.hash.length > 0) {
      lastHash.current = location.hash.slice(1)
    }

    if ((lastHash.current.length > 0) && (document.getElementById(lastHash.current) != null)) {
      setTimeout(() => {
        //  s
        const element = document
          .getElementById(lastHash.current)
        // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
        if (element) {
          const elementPosition = element.getBoundingClientRect().top + window.scrollY
          window.scrollTo({
            top: elementPosition - navbarHeight,
            behavior: 'smooth'
          })
        }
        // s
      }, 100)
    }
  }, [location])

  return null
}

export default ScrollToAnchor
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ktechgau profile image
Karla

Hello and thank you for this! Pardon my ignorance I am new to React JS, I have created a component, imported the function to the page I want to use it, but still not working, what am I missing please?

Collapse
 
squeasy profile image
Abdullah Malik

Any chance you still need help with this?

Collapse
 
fadelyang profile image
Fadela Numah Kadenz

It's simple and works, Thankyou