Scroll Progress Bar in Next js /React

Oct 21 20236 minutes
Scroll Progress Bar in Next js /React

A scroll progress bar is a visual indicator that shows how far a user has scrolled down a web page.

In this tutorial, we are going to create one for ourselves in React.

To display the current scroll percent we need to get the total scroll height and currently scrolled position and that’s what we are going to do in this tutorial.

Let’s start by setting up our project.

#Project Setup

As we are building a progress bar for React we need a React app already set up, in case if not you may create a new React or Nextjs project.

In my case, I already have created a React app with Vite, but don’t worry how you create your app has nothing to do with this tutorial We are mainly focusing on the ProgressBar component rather than whole app.

This is how my project looks right now.

image from tutorend.com

Currently, only two files are useful for us App.jsx and main.jsx

Here’s how App.jsx looks like

function App() {
  return (
    <>
      <div className="app text-center">
        <h1 className="text-8xl">Tutorend</h1>

        <p>Welcome to React Tutorials by Tutorend</p>

        <p className="text-2xl">
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Nesciunt,
          ipsam assumenda maiores amet itaque voluptate necessitatibus eveniet
          ipsum perferendis. Quasi officiis eius corrupti modi optio laborum
          aspernatur cum. Vel, debitis!
        </p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
        <p className="text-4xl my-8 ">Hello Coders!</p>
      </div>
    </>
  );
}

export default App;

As you can see there’s nothing important in the App component, just enough dummy content to make the page scrollable so that we can show scroll progress.

and here’s what main.js looks like

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)

Just the default code, but later we are going to import the progress bar component in this.

#Creating ProgressBar component

Now I am going to create a new component for showing the progress bar, in the src/components folder.

image from tutorend.com

Here’s the initial code for ProgressBar

import React from 'react'

function ProgressBar() {
  return (
    <div>ProgressBar</div>
  )
}

export default ProgressBar

Now we are going to create two divs in this component, one for progress-container and the other for progress-fill.

Progress-container: This is going to have a width of 100% and act as the container for the dynamically changing progress bar.

progress-fill: Initially the width of the progress fill is going to be 0 and while we scroll well programmatically change the width of the bar as we decrease or increase.

Let’s see this

<div
      id="progress-container"
      style={{
        height: "8px",
        width: "100%",
        backgroundColor: "#d1dced",
        position: "fixed",
        top: "0",
        left: "0",
        right: "0",
      }}
    >
      <div
        className="progress-fill"
        style={{
          height: "100%",
          backgroundColor: "blue",
          width: `${scrollPercentage}%`,
        }}
      >
       
      </div>

As you can see we have set the progress bar to be fixed on the to,

Set the background color of the progress container to gray and the progress fill to blue.

Also in progress fill instead of width value, we are using a variable by using template literal ( backticks), This variable is going to be a state in which the value is going to be changed dynamically when we scroll.

Now let’s see how we gonna do it.

First, we have to create the state/ variable with the name scrollPercentage.

 const [scrollPercentage, setScrollPercentage] = useState(0);

Now I am going to add an event listener to detect when we scroll and change the state according to the current scroll position

We have to do it inside the use effect as we need to access the window properties.


  useEffect(()=>{

    window.addEventListener("scroll", handleScroll);

    return()=>{
        window.removeEventListener("scroll", handleScroll)
    }

  },[])

In the above code, you can see I have added a scroll event listener which calls a function handleScroll upon scroll, In return you can see I am removing the event listener to avoid memory leaks as useEffect may run several times.

now let’s write the handle scroll function


  useEffect(()=>{

    const handleScroll = ()=>{
        const windowHeight = window.innerHeight;
        const documentHeight = document.documentElement.scrollHeight;
        const scrollY = window.scrollY;
        
        const scrollPercent = (scrollY / (documentHeight - windowHeight))*100 

        setScrollPercentage(scrollPercent)
        console.log(scrollPercent)
    }


    window.addEventListener("scroll", handleScroll);

    return()=>{
        window.removeEventListener("scroll", handleScroll)
    }

  },[])

In the function, you can see I am getting and total height of the window and calculating the current scrolled percentage according to the current scroll position

In the function, you can also see that I am updating the scrollPercetage` variable state and now we have made the scroll progress bar dynamic.

#Importing and using the ProgressBar component

Now we can import and use the component in any main components like Main.js or App.js or if you want this feature on any specific page then you can simply import and use this component on that specific page only, In my case I want his in the whole application so I am going to import it in main.js and use it inside the wrapper.

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import ProgressBar from "./components/ProgressBar";


ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <ProgressBar/>
    <App />
  </React.StrictMode>,
)

Now let’s see the result when we scroll.

image from tutorend.com

#Conclusion

Building the basic version of the Scroll ProgressBar component is very easy, but there’s a lot you can do with it like.

You can set it to any specific part of the page instead of just the top by changing the positions,

You can add more colors and animations

Basically, the possibility is endless and it depends upon your need.

I hope you learned something new from this tutorial, Happy coding.