paint-brush
How to Make a Silky Smooth Scroll in Reactby@BernardoGarza
17,313 reads
17,313 reads

How to Make a Silky Smooth Scroll in React

by Bernardo Garza LandaJuly 30th, 2020
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

React-scroll is a component to animate your vertical scroll, and it's effortless to use. In this article, I'm going to show you how to add it to your React Components. The Link component will allow us to animate our scrolling when we click on a link. We need to replace our Visual Studio Code tag with the Link component. We are using styled-components but, that's a topic for a future article. We're going to end up with this: "Live Demo with React"

People Mentioned

Mention Thumbnail

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - How to Make a Silky Smooth Scroll in React
Bernardo Garza Landa HackerNoon profile picture

Have you ever been working on a project and wanted to scroll smoothly through your app?

With

react-scroll
you'll be able to do that in less than 10 minutes!

react-scroll is a component to animate your vertical scroll, and it's effortless to use. In this article, I'm going to show you how to add it to your React Components.

After finishing this article, you're going to end up with this:

Live Demo

Feel free to clone my GitHub repository if you want to code along!

git clone [email protected]:bernardogarza/react-scroll-tutorial.git

Make sure you're in the

react-smoothless
branch.

git checkout react-smoothless

Let's get into it

If you are working on my cloned repository, make sure to run

npm install
or
yarn
(this might take a few minutes).

If you are starting a project from scratch, you'll need to install the npm package.

npm install react-scroll

// or

yarn add react-scroll

First things first, let's start the server, this will automatically refresh your browser when you save a file. You can view it in the browser at

localhost:3000
.

npm start

//or

yarn start

The Link Component

The first thing we need to do to start using react-scroll is importing the

Link
component from
react-scroll
into the component where we have our links, in this case, the
Navbar
component.

The Link component will allow us to animate our scrolling when we click on a link.

// navbar.component.jsx

import React from 'react';
import styled from 'styled-components';

import { Link } from 'react-scroll';

As you can see, we are using styled-components but, that's a topic for a future article. Let's focus on the

Link
component for now.

After we imported the Link component, we need to replace our

<a>
tags with the Link component.

I recommend this extension for Visual Studio Code called Auto Rename Tag, it automatically changes your closing tag while editing the opening one. It will save you a lot of time and confusion while editing tags.

// navbar.component.jsx

export default function Navbar() {
  return (
    <NavbarStyled>
      <div className="header">
        <Link activeClass="active" to="section1" spy={true} smooth={true} duration={1000}>
          Section 1
        </Link>
        <Link activeClass="active" to="section2" spy={true} smooth={true} duration={1000}>
          Section 2
        </Link>
        <Link activeClass="active" to="section3" spy={true} smooth={true} duration={1000}>
          Section 3
        </Link>
      </div>
      <div className="scrolling-buttons">
        <Wrapper>
          <OnScreenScrolling />
        </Wrapper>
      </div>
    </NavbarStyled>
  );
}

You might be wondering what are all those properties inside the

Link
component, well, allow me to explain it to you:

  • activeClass
    : class applied when the element is reached. This means that whenever you click on the Link component, that class will be applied to that Link component.
  • to
    : target to scroll to. Here we are going to put the id of the element we want to scroll to.
  • spy
    : make Link selected when the scroll is at its target position.
  • smooth
    : animate the scrolling. That's basically the whole point of this.
  • duration: time of the scroll animation - can be a number (milliseconds) or a function (
    function (scrollDistanceInPx) { return duration; }
    ), that allows more granular control at run-time.

Don't forget that the component that you want to link should have the same id that we used on the

to
property that we have in the
Link
component. Here is an example:

// section1.component.jsx

import React from 'react';
import styled from 'styled-components';

import Wrapper from '../wrapper/wrapper.component';

const Section1Styled = styled.div`
  background-color: darkviolet;
  .active {
    border-bottom: 1px solid white;
  }
`;

export default function Section1() {
  return (
    <Section1Styled id="section1">
      <Wrapper>
        <h1>Section 1</h1>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipisicing elit. Placeat blanditiis adipisci eaque animi repellat
          atque assumenda corporis quidem nostrum ea, nulla qui cupiditate suscipit, quisquam voluptas mollitia ex iusto
          voluptates.
        </p>
      </Wrapper>
    </Section1Styled>
  );
}

You can see that we have

to="section1"
on our first
Link
component.

This is how our file should look:

//navbar.component.jsx

import React from 'react';
import styled from 'styled-components';

import { Link } from 'react-scroll';
import OnScreenScrolling from '../on-screen-scrolling/on-screen-scrolling.component';
import Wrapper from '../wrapper/wrapper.component';

const NavbarStyled = styled.div`
  font-size: 24px;
  position: fixed;
  width: 100%;
  .header {
    background: black;
    padding: 40px;
    display: flex;
    justify-content: space-around;
    margin: 0;
    color: white;
    * {
      cursor: pointer;
    }
    .active {
      border-bottom: 1px solid white;
    }
  }
  .scrolling-buttons {
    display: flex;
    flex-direction: column;
  }
`;

export default function Navbar() {
  return (
    <NavbarStyled>
      <div className="header">
        <Link activeClass="active" to="section1" spy={true} smooth={true} duration={1000}>
          Section 1
        </Link>
        <Link activeClass="active" to="section2" spy={true} smooth={true} duration={1000}>
          Section 2
        </Link>
        <Link activeClass="active" to="section3" spy={true} smooth={true} duration={1000}>
          Section 3
        </Link>
      </div>
      <div className="scrolling-buttons">
        <Wrapper>
          <OnScreenScrolling />
        </Wrapper>
      </div>
    </NavbarStyled>
  );
}

And that's it, just like that you have

react-scroll
working on your Navbar links. Pretty easy, don't you think?

There's one more thing that I want to cover in this article, it's going to be super easy too! and I promise it will be useful.


The animateScroll

You might have noticed some random buttons in our app, well, let's make those buttons functional.

The

animateScroll
will allow us to perform more specific types of scrolling. We are not going to be limited to just scrolling straight to
divs
with
ids
. Using this we are going to be able to scroll from top to bottom and vice versa and scroll a specific amount of pixels per click.

Let's start by importing the

animateScroll
into our
on-screen-scrolling
file.

// on-screen-scrolling.component.jsx

import React from 'react';
import styled from 'styled-components';

import { animateScroll as scroll } from 'react-scroll';

You can see that we are importing

animateScroll as scroll
, which is for replacing the name of the component to make it easier to write. You can give it the name you want. It would work the same way if we added this into our
OnScreenScrolling
function:

 let scroll = animateScroll;

Now that we have imported

animateScroll
let's start working with the functions.

To assign custom scrolling to our buttons, we will need to create functions that will be called using an

onClick handler
. The
onClick handler
allows you to call a function and perform an action when an element is clicked.

First, we need to create our functions, these need to be inside of the

OnScreenScrolling
function. These functions are pretty straight forward.

Let's start with the functions that are going to scroll up.

The first one is going to be for scrolling to the top of our page.

// on-screen-scrolling.component.jsx

function scrollToTop() {
  scroll.scrollToTop();
}

The scroll to top and scroll to bottom functions are pretty self-explanatory, there is not much to say about them.

Now we are going to add a function to scroll 300 pixels up.

// on-screen-scrolling.component.jsx

function scrollMoreUp300() {
  scroll.scrollMore(-300);
}

As you can see, the function is taking an argument of -300, that argument is the pixels that we want to scroll. In this case, we want to scroll up, so we need to have a negative amount of pixels for that to happen.

This last one is the same as the one that we just talked about but for scrolling 100px instead of 300px.

// on-screen-scrolling.component.jsx

function scrollMoreUp100() {
  scroll.scrollMore(-100);
}

Remember that the values of the arguments in these functions are negative because we want to scroll up.

Now, let's do the same but for down scrolling.

Let's start with the function to scroll to the bottom of the page. I bet you can guess how it is going to look like.

// on-screen-scrolling.component.jsx

function scrollToBottom() {
  scroll.scrollToBottom();
}

Really intuitive, don't you think?

Let's move on to the pixel specific scrolling functions. These are also pretty intuitive, these are going to be exactly as the ones we used before but with positive values instead.

// on-screen-scrolling.component.jsx

function scrollMoreDown300() {
  scroll.scrollMore(300);
}
// on-screen-scrolling.component.jsx

function scrollMoreDown100() {
  scroll.scrollMore(100);
}

It makes sense, doesn't it?

Now let put these functions to work. We will add them to our

<button>
tags using an
onClick
handler, as I mentioned earlier.

As you might already know, we need to use curly brackets to pass the functions inside our tag's properties, basic JSX syntax.

// on-screen-scrolling.component.jsx

<OnScreenScrollingStyled>
  <div className="top button-row">
    <div>
      <button onClick={scrollMoreUp100}>Scroll Up 100px</button>
    </div>
    <div>
      <button onClick={scrollToTop}>Scroll to Top</button>
    </div>
    <div>
      <button onClick={scrollMoreUp300}>Scroll Up 300px</button>
    </div>
  </div>
  <div className="bottom button-row">
    <div>
      <button onClick={scrollMoreDown100}>Scroll Down 100px</button>
    </div>
    <div>
      <button onClick={scrollToBottom}>Scroll to Bottom</button>
    </div>
    <div>
      <button onClick={scrollMoreDown300}>Scroll Down 300px</button>
    </div>
  </div>
</OnScreenScrollingStyled>

There is not a lot to explain here, we just added the

onClick
handler inside each button and passed the function that we want them to call.

This is how your file should look by now:

import React from 'react';
import styled from 'styled-components';

import { animateScroll as scroll } from 'react-scroll';

const OnScreenScrollingStyled = styled.div`
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  .button-row {
    width: 100vw;
    display: flex;
    justify-content: space-between;
    div {
      margin: 0 10px;
    }
    button {
      padding: 3px;
      font-weight: bold;
      cursor: pointer;
    }
  }
  .bottom {
    margin-bottom: 115px;
  }
`;

export default function OnScreenScrolling() {
  // Scroll up
  function scrollToTop() {
    scroll.scrollToTop();
  }
  function scrollMoreUp300() {
    scroll.scrollMore(-300);
  }
  function scrollMoreUp100() {
    scroll.scrollMore(-100);
  }

  // Scroll down
  function scrollToBottom() {
    scroll.scrollToBottom();
  }
  function scrollMoreDown300() {
    scroll.scrollMore(300);
  }
  function scrollMoreDown100() {
    scroll.scrollMore(100);
  }

  return (
    <OnScreenScrollingStyled>
      <div className="top button-row">
        <div>
          <button onClick={scrollMoreUp100}>Scroll Up 100px</button>
        </div>
        <div>
          <button onClick={scrollToTop}>Scroll to Top</button>
        </div>
        <div>
          <button onClick={scrollMoreUp300}>Scroll Up 300px</button>
        </div>
      </div>
      <div className="bottom button-row">
        <div>
          <button onClick={scrollMoreDown100}>Scroll Down 100px</button>
        </div>
        <div>
          <button onClick={scrollToBottom}>Scroll to Bottom</button>
        </div>
        <div>
          <button onClick={scrollMoreDown300}>Scroll Down 300px</button>
        </div>
      </div>
    </OnScreenScrollingStyled>
  );
}

And that's it! We have fully functional scrolling buttons and links. The

animateScroll
is a little bit harder than
Link
, but it's still straightforward and worth it.

There are more things that we can do with react-scroll. You can find more examples and more complex things that this package is capable of doing In the GitHub repository. I encourage you to experiment with it and find out what it's capable of. BE CREATIVE!


Thank you for reading my article. I hope you found it useful, please follow me on GitHub and give the repo a star if you enjoyed building it.

“I guess I’ve been working so hard, I forgot what it’s like to be hardly working.” - Michael Scott

Catch me on - Twitter | LinkedIn | GitHub