DEV Community

Cover image for Scroll to an Element in React
Bernard Bado
Bernard Bado

Posted on • Originally published at upbeatcode.com on

Scroll to an Element in React

When I'm thinking about the things I learned way too late in my React journey. There is one feature that immediately comes to my mind - scrolling. I decided to sum up everything I know about the scrolling and scroll effects. And put it in this blog post. Let's start with the single most asked question about scrolling. How to scroll to an element in React app?

Scroll to an Element

The way to scroll to an element in React is a little different than other frameworks. The most simple way is to use ref to store the reference of the element that you want to scroll to. And call myRef.current.scrollIntoView() to scroll it into the view.

The whole implementation using a functional component.

import React, { useRef } from 'react';

const App = () => {
  const scollToRef = useRef();

  return (
    <div className="container">
      <button onClick={() => scollToRef.current.scrollIntoView()}>
        Scroll
      </button>
      <div ref={scollToRef}>You scrolled to me</div>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

And here is the class-based version.

import React, { createRef } from 'react';

class App extends Component {
  constructor(props) {
    super(props);
    this.scollToRef = createRef();
  }

  render() {
    return (
      <div className="container">
        <button onClick={() => this.scollToRef.current.scrollIntoView()}>
          Scroll
        </button>
        <div ref={this.scollToRef}>You scrolled to me</div>
      </div>
    );
  }
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Scrolling to an element is a powerful technique and I can see a lot of applications for it. But sometimes, you don't want to scroll to a specific element. What should you do in this case? You'll find out in the next section.

Scroll to an Exact Location

React provides a scrollTo function that lets you scroll to a given location. A good application for this function is to scroll to the bottom of the page, or back to the top. This function takes two arguments: the first is the position of where you want to scroll and the second is the animation duration (optional). The syntax for this function is as follows: scrollTo(x, y).

The usage in React isn't any different from other frameworks. This is because of the fact that scrollTo function can be accessed directly from Window object.

import React from "react";

const App = () => {
  return (
    <div className="container">
      <button onClick={() => window.scrollTo(0, window.innerHeight)}>
        Scroll to bottom
      </button>
      <button onClick={() => window.scrollTo(0, 0)}>Scroll top top</button>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

You can also call scrollTo function with ScrollToOptions object as a parameter. I'm using this when I need to specify additional scrolling behavior, e.g. smooth scrolling.

import React from "react";

const App = () => {
  return (
    <div className="container">
      <button
        onClick={() =>
          window.scrollTo({
            left: 0,
            top: window.innerHeight,
            behavior: "smooth",
          })
        }
      >
        Scroll to bottom
      </button>
      <button
        onClick={() =>
          window.scrollTo({
            left: 0,
            top: 0,
            behavior: "smooth",
          })
        }
      >
        Scroll top top
      </button>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Benefits of Scroll Effect

Websites are made to be navigated by scrolling down. However, this can cause eye strain and is mentally taxing for the user. To combat this, many new websites implement a "scrolling effect" that scrolls in a smooth linear path so you don't have to scroll as often or as fast and find what you're looking for more efficiently.

The idea of the scrolling effect is that it encourages users to scan through different areas of a website. Not just focus on one area at a time. Websites often use this effect to highlight certain parts of their page or draw attention to content that they want their users to look at next.

Popular Scrolling Libraries for React

As the popularity of React has grown, so has the number of libraries that are available for it. Below is a list of some popular scrolling libraries that you can use in your React project.

Scroll Magic

ScrollMagic is a JavaScript library that makes it super easy to react to the user's current scroll position. It is perfect if you want to:

  • Animate based on scroll position.
  • Pin an element starting at a specific scroll position.
  • Toggle CSS classes based on scroll position.
  • Add parallax effects to your website.
  • Create an infinitely scrolling page.
  • Add callbacks at specific scroll positions or while scrolling past a specific section.

React Scroll

With more than 200k weekly downloads and 3.5k start on Github, it's safe to say that react-scroll is the most popular React scrolling library out there. It covers a lot of common use cases like:

  • Scrolling to an exact page location
  • Scrolling to an element
  • Scrolling to an element within the container
  • Callbacks at specific scroll positions or while scrolling past a specific section.

This library covers many use-cases. However, I tried to put together the most basic example. And this is how the implementation goes.

import React, { Component } from "react";
import {
  Link,
  Element,
  Events,
  animateScroll as scroll,
  scroller,
} from "react-scroll";

import "./ReactScroll.css";

class ReactScroll extends Component {
  componentDidMount() {
    Events.scrollEvent.register("begin", () => {
      console.log("begin", arguments);
    });

    Events.scrollEvent.register("end", () => {
      console.log("end", arguments);
    });
  }

  scrollToTop = () => {
    scroll.scrollToTop();
  };

  scrollTo = () => {
    scroller.scrollTo("scroll-to-element", {
      duration: 800,
      delay: 0,
      smooth: "easeInOutQuart",
    });
  };

  scrollToWithContainer = () => {
    let goToContainer = new Promise((resolve) => {
      Events.scrollEvent.register("end", () => {
        resolve();
        Events.scrollEvent.remove("end");
      });

      scroller.scrollTo("scroll-container", {
        duration: 800,
        delay: 0,
        smooth: "easeInOutQuart",
      });
    });

    goToContainer.then(() =>
      scroller.scrollTo("scroll-container-second-element", {
        duration: 800,
        delay: 0,
        smooth: "easeInOutQuart",
        containerId: "scroll-container",
      })
    );
  };

  componentWillUnmount() {
    Events.scrollEvent.remove("begin");
    Events.scrollEvent.remove("end");
  }

  render() {
    return (
      <main className="react-scroll-page">
        <nav>
          <ul>
            <li>
              <Link to="section-1" spy={true} smooth={true}>
                Section 1
              </Link>
            </li>
            <li>
              <Link to="section-2" spy={true} smooth={true}>
                Section 2
              </Link>
            </li>
            <li>
              <Link to="section-3" spy={true} smooth={true}>
                Section 3
              </Link>
            </li>
            <li>
              <button onClick={scroll.scrollToBottom}>Scroll To Bottom</button>
            </li>
            <li>
              <button onClick={scroll.scrollToTop}>Scroll To Top</button>
            </li>
            <li>
              <button onClick={() => scroll.scrollMore(500)}>
                Scroll 500 More!
              </button>
            </li>
            <li>
              <button onClick={() => scroll.scrollMore(-500)}>
                Scroll 500 Less!
              </button>
            </li>
            <li>
              <button
                to="scroll-container-second"
                onClick={() => this.scrollToWithContainer()}
              >
                Scroll to second element within container
              </button>
            </li>
          </ul>
        </nav>

        <Element name="section-1" className="page-section page-section-1">
          Section 1
        </Element>
        <Element name="section-2" className="page-section page-section-2">
          Section 2
        </Element>
        <Element name="section-3" className="page-section page-section-3">
          Section 3
        </Element>
        <Element className="container" id="scroll-container">
          <Element name="scroll-container-first">
            First element inside container
          </Element>

          <Element name="scroll-container-second">
            Second element inside container
          </Element>
          <Element name="scroll-container-third">
            Third element inside container
          </Element>
        </Element>
      </main>
    );
  }
}

export default ReactScroll;
Enter fullscreen mode Exit fullscreen mode

As you can see from the examples, it's possible to:

  • Scroll between sections.
  • Scrolling to the top.
  • Scrolling to the bottom.

React scroll library showcase

But that's not all. You can also:

  • Off scroll position in a positive or negative direction.
  • Scroll to an element within the container.

React scroll library showcase

React Hash Scroll

React Hash Scroll is a popular library used in many React projects. It aims to be the simplest way to implement hash routing. The library makes it easier for developers to make their web app work with hash navigation. With just a few lines of code, we can achieve smooth navigation between different page sections.

import React from "react";
import { Link } from "react-router-dom";
import { HashScroll } from "react-hash-scroll";

const HashScrollPage = () => {
  return (
    <main className="page">
      <nav>
        <ul>
          <li>
            <Link to="/hash-scroll#hash-section-1">Go To Section 1</Link>
          </li>
          <li>
            <Link to="/hash-scroll#hash-section-2">Go To Section 2</Link>
          </li>
          <li>
            <Link to="/hash-scroll#hash-section-3">Go To Section 3</Link>
          </li>
        </ul>
      </nav>
      <article>
        <HashScroll hash="#hash-section-1">
          <section>Section 1</section>
        </HashScroll>
        <HashScroll hash="#hash-section-2">
          <section>Section 2</section>
        </HashScroll>
        <HashScroll hash="#hash-section-3">
          <section>Section 3</section>
        </HashScroll>
      </article>
    </main>
  );
};

export default HashScrollPage;
Enter fullscreen mode Exit fullscreen mode

With a little bit of CSS magic, the code above will result in the following.

Page scrolling in React

React Scroll Parallax

If you're a fan of the parallax effect. I guarantee you'll love this library. React scroll parallax library provides components to create parallax scroll effects for any DOM elements. It uses a single scroll listener to add vertical or horizontal scroll offsets to elements based on their position in the viewport. It's optimized for performance and works for both client/server-side rendered apps.

With just a little bit of code (and much more design skills), you can achieve stunning results like the example below. Credits to jscottsmith

image-scroll-paralax

Concluding Thoughts

Every time I'm building user interfaces, I'm telling myself one thing. It's your job as a developer to make the user experience as smooth as possible. If it means taking the user by the hand and pointing him to every single piece of content on my website, so be it.

Navigating between different pages of the website is pretty straightforward and can be done using links. But when it comes to navigation between different places on the same page, scrolling is the way to go. And today, you learned how to do it. You learned how to scroll to an element in React app. You learned how to scroll into a specific position. And you also learned what libraries are available for scrolling. Now, it's up to you to get to work and start using this knowledge in your react app.

Top comments (0)