How to create a Scroll to Top Button with React
Silvia España Gil

Silvia España Gil @silviaespanagil

About: iOS Developer 📱👩🏻‍💻 Women Techmaker Ambassador. Mentor at Step4ward. Speaker

Location:
Spain
Joined:
Jul 6, 2021

How to create a Scroll to Top Button with React

Publish Date: Aug 24 '21
108 18

Hola Mundo!


So this is my first coding post and am really excited about it 👩‍🎤✨

Thing is that, when I was creating my Portfolio I decided I didn't want to do a sticky menu because well...not a fan of it. However I noticed that from the user perspective, scrolling through the page all the way to the top is not nice at all 🙅.

At the same time, while I was reading some old messages in a WhatsApp group I noticed the Scroll-to-Bottom button that appears on the conversation capture of how the button looks like Eureka!💡, so that was my hipothesis: what if I tried to create a button to do the same but the other way around!

I did it and I loooooooooove it 💓. It's one of my favorites components and now I use it in a lot of projects because:

  • It makes navigation much more easier 🖱️

  • The devil is in the details 😈, this may be small but it adds up a lot to your user experience

  • Is really simple to do 🤗

So this is my "How to do a Scroll to top button with React functional components"


What does the button does - The logic behind 🧠


After the user start scrolling, the button will appear in a corner allowing it to click it so they can run all the way to the top without having to scroll anymore.

Gif of the go-to-top button works

For doing so, we need, of course, a button. The button can have a text, an emoji or an icon whatever you feel suits it better..

We will also need to hear the scroll position so we can hide🙈 or show🐵 our button and finally we will need to handle the scrolling action itself.

So these are the steps:

1- Create and style the button
2- Hear the user position and handle the display
3- Handle the scroll to top action
4- Send props to component

Let's get to it!💪


Creating the button 🔼

I started by creating a new component that I called "GoTop.js". I highly recommend to create a new component so in the future, you can reuse ♻️ it if you want to.

This is pretty much a dumb component that will render the button itself and that will receive via props the hidding and the action methods 🔨.

For my button I used a fontawesome icon as I think it looks really clean and simple.



//goTop.js COMPONENT

const GoTop = (props) => {
  return (
    <>
      <div className={props.showGoTop} onClick={props.scrollUp}>
        <button className="goTop">
          <i className="goTop__text fas fa-chevron-up" />
        </button>
      </div>
    </>
  );
};
export default GoTop;


Enter fullscreen mode Exit fullscreen mode

For the styles 💅 I worked with SASS: my button only has a display:block; and the goTop__text class has everything else: position, colours, size, shadows and a little hover action. Don't forget to make it fixed!

Code showing how I styled my component

Step one: done.

✔️ Create and style the button


Hearing the user position 👂 and showing the button


For the button to render we need to know where the user is. We don't want the button to show if there's no way up to go 🛑

So we will start declaring our scroll position with an initial state of 0
const [scrollPosition, setSrollPosition] = useState(0);

Now, as we also need to show or hide the button, we will declare another state, this time for the "showing".
const [showGoTop, setshowGoTop] = useState("goTopHidden");.

In my oppinion, I think the easiest way to manage this state is to add one or other class, having the "goTopHidden" class with a display: none; style and a "goTop" class that, as you have seen before states a display: block; that makes it visible.

This will be sent 📤 via prop to my component so the div that wraps up the button, receives the corresponding class.

Handle the display 👀


This handler will set new states to the states we just declared. For doing so, we are gonna use the window.pageYOffset; this property "returns the number of pixels that the document is currently scrolled vertically" read more...

So first thing first, our handler will take this information and set it in our position state. Now that we know where our user is🙋, we can tell the handler that when the user reaches a certain position something must happen. According to our code it will change the class that hides our button.

As you can see on the code below, when the scrollPosition is greater than 50 (px) it will change the element class to "GoTop" else, it will set the class that hides the button.



//DISPLAY HANDLER
const handleVisibleButton = () => {
    const position = window.pageYOffset;
    setSrollPosition(position);

    if (scrollPosition > 50) {
      return setshowGoTop("goTop");
    } else if (scrollPosition < 50) {
      return setshowGoTop("goTopHidden");
    }
  };


Enter fullscreen mode Exit fullscreen mode

To wrap up this step we will add an eventListener to our window that will trigger the method. For this we will need to use the useEffect Hook with a simple window.addEventListener that will call our handleVisibleButton method.



//SCROLL LISTENER
useEffect(() => {
    window.addEventListener("scroll", handleVisibleButton);
  });


Enter fullscreen mode Exit fullscreen mode

Step two: done.

✔️ Hear the user position and handle the display


Handling the scroll action🖱️


This handler will be triggered by the user click and its function is very simple: to scroll up the user.

In order to do this we will need to use another Hook: useRef(), that we will declare in a constant const refScrollUp = useRef();

Having this constant declared now we have to call it in our JSX in the element we want to use as reference. Understanding that we want to send the user all the way up, we will have to call it in an element that is in the top of our page 🔝

I decided to add a <div> tag on top of everything as reference.



//REF IN JSX
function App() {
 //code
  return (
    <>
      <div ref={refScrollUp}> </div>
      <Header />
      <AboutUs />
     </>
  );
}

export default App;


Enter fullscreen mode Exit fullscreen mode

Now it comes the last step: our handling method. In our method we will have to use the property current of our Hook. As we referenced an element of our DOM, React will assign that element as "current".

We also will need to use the scrollIntoView() method. This method will make that the element on which scrollIntoView() is called is visible to the user.

So our handling method will use the reference we created and with the scrollIntoView, we will be
able to actually scroll our user all the way to the top.

Our function will look like this:



//SCROLL UP HANDLER

const handleScrollUp = () => {
    refScrollUp.current.scrollIntoView({ behavior: "smooth" });
  };


Enter fullscreen mode Exit fullscreen mode

P.D: I added a behavior: "smooth" because we want the scroll to look soft.

Step three: done.

✔️ Handle the scroll-to-top action


Sending everything via props ✈️


Now that all the things are in motion we have to send via props two things: the state for the button, so it changes correctly and the handleScrollUp funcion that we will call onClick.

<GoTop showGoTop={showGoTop} scrollUp={handleScrollUp} />



//PROPS
const GoTop = (props) => {
  return (
    <>
      <div className={props.showGoTop} onClick={props.scrollUp}>
      //BUTTON CODE
    </div>
  );
};
export default GoTop;


Enter fullscreen mode Exit fullscreen mode

Step four: done.

✔️ Send props to component


It's done 🎆🎇

After this four steps you should have a Go-to-Top button that is totally functional💯

This is my take for the Go-to-Top Button in React using functional components. I really hope this works for you and if you have any question, feel free to ask so, if I have the answer I'll answer and if not...we can Google it together 😅

Joke code about being able to answer things

Comments 18 total

  • Mike Talbot ⭐
    Mike Talbot ⭐Aug 24, 2021

    Really nice post :)

    One thing - your useEffect(()=>window.addListener(... is being called on every re-render so you will end up with lots of them added. You should return a function to remove the listener so it tidies up and possibly rewrite things a bit so you can actually only do it on mount/unmount with deps of []. Care needs to be taken with that though because the you need to be sure that the handler can work in cases when it wasn't added on the same render (it's a closure on the time the deps change).

    • Silvia España Gil
      Silvia España GilAug 24, 2021

      Thank you very much Mike, I'll put at eye on it and see if I find a solution so it works in every scenario!

    • hassanKhademi
      hassanKhademiAug 25, 2021

      useEffect(() => {
      window.addEventListener("scroll", handleVisibleButton);
      },[]);
      For fix issue this way is great
      execute when component mounting
      One listener

      • Hamid Shoja
        Hamid ShojaOct 17, 2022

        what about removing the listener when unmouning,

        
        useEffect(() => {
        const e = window.addEventListener("scroll", handleVisibleButton);
        
        return ()=> window.removeEventListener('scroll',handleVisibleButton);
        },[]);
        
        
        Enter fullscreen mode Exit fullscreen mode
  • bvince77
    bvince77Aug 25, 2021

    Nice little feature

  • Chetan Atrawalkar
    Chetan AtrawalkarAug 25, 2021

    Thank you so much for this post because I'm already working on this for my personal portfolio 🤗💜 @silviaespanagil

  • Sajidur Rahman
    Sajidur RahmanAug 25, 2021

    I joined here, to encourage you. As you are very excited about your first post. That's a nice post. Keep it up ☺️

  • Erlangga
    ErlanggaAug 29, 2021

    Nice
    Thanks

  • Otto Vector
    Otto VectorJan 23, 2022

    This (I think) more shorter and in one component
    No styles info, because it is very hard to qick-understand.
    You can Use youre beatiful style.

    ///////////////////////////////////////////////////
    import React, { useEffect, useState } from 'react'
    import styles from './go-top-button.module.scss'

    const GoTopButton = () => {

    const [ showGoTop, setShowGoTop ] = useState( false )
    
    const handleVisibleButton = () => {
        setShowGoTop( window.pageYOffset > 50 )
    }
    
    const handleScrollUp = () => {
        window.scrollTo( { left: 0, top: 0, behavior: 'smooth' } )
    }
    
    useEffect( () => {
        window.addEventListener( 'scroll', handleVisibleButton )
    }, [] )
    
    return (
        <div className={ showGoTop ? '' : styles.goTopHidden } onClick={ handleScrollUp }>
            <button type={'button'} className={ styles.goTop }>
                //use Material Icon
                <span className={ styles.goTopIcon }>expand_less</span>
            </button>
        </div>
    )
    
    Enter fullscreen mode Exit fullscreen mode

    }

    export default GoTopButton

  • АнонимFeb 7, 2025

    [hidden by post author]

  • jeff sealsre
    jeff sealsreFeb 7, 2025

    Backless tops strike the perfect balance between elegance and boldness. They exude confidence, allowing for a subtle Backless tops yet striking statement. Whether styled casually with jeans or paired with a sleek skirt for a night out, they add an effortless charm. The open-back detail enhances posture, creating a graceful silhouette. Perfect for warm days or layering, backless tops redefine sophistication with a touch of daring allure.

Add comment