Hackernoon logoHow to Make a Silky Smooth Scroll in React by@BernardoGarza

How to Make a Silky Smooth Scroll in React

Author profile picture

@BernardoGarzaBernardo Garza Landa

Front-end lover

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:
Feel free to clone my GitHub repository if you want to code along!
git clone git@github.com: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

Tags

The Noonification banner

Subscribe to get your daily round-up of top tech stories!