Build a Scroll Indicator JS Class!
Published: 2023-09-22 08:16:25

{% embed https://www.youtube.com/watch?v=fViYIq0xGc0 %}

For those of you who are lazy readers (which might still happen on a blogging site, who knows), you can check out the video above!

For the rest, continue on! 

(You ready?)
## The struggle…

Have you ever scrolled down a page that never seemed to end? ( I certainly have, way too many time).

“Omg, am I supposed to read all that?” is probably what you’re thinking at those moments!

While scrolling down you wonder, how much longer will this take?

(All of you recipe blog posts out there, you know exactly that I'm talking about you!)

That's why today, we're building a scroll indicator together - a simple solution to this annoyingly common problem.

Let’s get started, shall we?


![Uploading image](...)

## What is a scroll indicator?

Put simply, it's a bar (mostly below the navbar) that shows the user how far he or she has scrolled down on the page. 

So good, so far - but why would you want it in the first place?

Simple, my friend -  the web page seems way less confusing in your user's mind and offers a much better user experience (who doesn’t want that?).

This makes especially sense in longer pages where we want to give the use some sign that this will not go on forever!

So, why this long blog post then?

## There’s a special catch…

And here it is!

In this tutorial, you will build a JS Class that lets you insert a scroll indicator into any webpage you want.

Ok, before you wonder “why would I want that?”, let me explain.

Often, you might use a tag management system like Google Tag Manager to insert specific elements only into selected pages (or when meeting certain conditions, such as desktop vs mobile etc).

In those moments, you want a simple solution that doesn’t require you to go into the source code and add even more HTML, CSS, and JS!

Using a JS Class makes this process way easier and more streamlined.

Instead of inserting HTML, CSS, and JS separately into every page you target (what a pain), you simply create an instance of your new scroll indicator class and … that’s it!

Super simple.

To sum it up - a JS class makes your code more:

- Reusable
- Customizable
- Flexible

## 1. Getting started

Let’s start by defining our class called “ScrollIndicator”.

First, we define out class.

```jsx
class ScrollIndicator {}
```

In there, we specify a constructor which takes certain parameter that we want to pass.

These are:

1. **Selector** - A CSS Selector that lets us target the parent container (in our case, our nav bar)
2. **Position** - This lets us specify a position when we use `insertAdjacentHTML`. In our case, it is not needed because we position our scroll indicator absolute, but hey, you can play around with the code the way you want!
3. **Color** - This is the color that we want to display as the scroll indicator fills up.
4. **Window** - Lastly, we take in the window object, so we can then add the scroll- Event Listener

```jsx
// start class
class ScrollIndicator {
    constructor(selector, position, color, window) {
        this.selector = selector;
        this.position = position;
        this.color = color;
        this.window = window;
        this.scrollBar = null;
        this.filling = null;
        // init
        this.init()
    }
}
```

Next, we add the methods that we want to call.

These are

1. **insertParentElement()** - this will insert the scroll indicator into the website
2. **insertFillingElement()** - this will insert the dynamic element of the scroll bar that will change colors
3. **addScrollListener()** - this adds the scroll listener to our window object, so we can then do something as we scroll
4. **getScrollPercentage()** - This will calculate the scroll percentage (meaning how far we’ve scrolled down on the page). We need that number in order to know how we much color we add to our scrollbar
5. **init()** - Lastly, I like to add an init method that calls all of the above-mentioned methods. As you can see in the constructor, we call this.init() everytime we create a new instance of our scrollbar

```jsx
// start class
class ScrollIndicator {
    constructor(selector, position, color, window) {
        this.selector = selector;
        this.position = position;
        this.color = color;
        this.window = window;
        this.scrollBar = null;
        this.filling = null;
        // init
        this.init()
    }
    insertParentElement() {
			// follows in a moment
    }
    insertFillingElement() {
      // follows in a moment
    }
    addScrollListener() {
			// follows in a moment
    }
    getScrollPercentage() {
			// follows in a moment
    }
    init() {
        this.insertParentElement();
        this.insertFillingElement();
        this.addScrollListener();
    }
}
```

## 2. Defining the methods

Now, let’s define the values one by one:

### insertParentElement()

Here, we first get a reference to the DOM element where we want to insert out scrollbar and we save it as `this.container`.

Then, we create the container of our scrollbar `this.scrollBar` which we want to insert inside of the previously found DOM element (which in our case will be a navbar).

For the styles, we do a light grey background (#333) that spans the entire screen width (100vw), has a height of 10 pixels and is positioned at the bottom of the parent container (position: absolute; bottom: 0)

Lastly, we add it into `this.container`.

Easy, right? Let’s move on

```jsx
// ...
insertParentElement() {
        this.container = document.querySelector(this.selector);
        this.scrollBar = document.createElement('div');
        this.scrollBar.classList.add('scroll-indicator');
        // style scrollbar
        this.scrollBar.style.background = '#eee';
        this.scrollBar.style.width = '100vw';
        this.scrollBar.style.height = '10px';
        this.scrollBar.style.position = 'absolute';
        this.scrollBar.style.bottom = '0';

        // insert scrollbar container
        this.container.insertAdjacentElement(this.position, this.scrollBar);
    }
// ...
```

### insertParentElement()

This is the element that will sit on top of the grey bar and fills with color as we scroll down.

Here, we create a div-element under `this.filling` which should fill the entire height of `this.scrollBar` and have the color that we defined in our constructor under `this.color`.

**IMPORTANT** - The width is the magical element here - it is set to 0 at the beginning, but we will change it dynamically as we scroll down the page. That’s what will make our colored bar grow or shrink!

Lastly, we add `this.filling`into our parent container `this.scrollBar`.

```jsx
// ...
insertFillingElement() {
        this.filling = document.createElement('div');
        this.filling.classList.add('scroll-indicator__bar');
        this.filling.style.width = "0%";
        this.filling.style.height = "100%";
        this.filling.style.background = this.color;
        this.scrollBar.insertAdjacentElement('afterbegin', this.filling);
    }
// ...
```

### addScrollListener()

This part is easy, too!

All we do is set an event listener to our window object that listens for a scroll event.

So every time we scroll down or up, the callback function is fired!

Inside our function, we get the current scroll percentage by calling the method `this.getScrollPercentage`(it’s already in the name,right). We’ll defined that method in just a second.

Then all we have to do is change the width of `this.filling` by using the current scroll percentage and adding the “%” sign.

No biggie!

```jsx
// ...
addScrollListener() {
        this.window.addEventListener('scroll', () => {
            const scrollPercentage = this.getScrollPercentage();
            this.filling.style.width = scrollPercentage + "%";
        })
    }
// ...
```

### addScrollListener()

We’re almost there, promised!

It’s time to define our method `getScrollPercentage`which we call inside of `addScrollListener`.

As a return value, we want the current position on the page compared to the entire length of the page - our scroll percentage!

To get that, we define three things

**windowHeight**

- the height of our current window (from the top of what we see to the bottom of what we see). The windowHeight can change as we resize our browser window.
- We get it by calling `window.innerHeight`
- For example, it could be 500px if we our browser window has a height of 500px

**pageHeight**

- this is the height of the entire document (all the way from the top to the very bottom).
- We get it by calling `document.body.scrollHeight`.
- For example, this could be 2000 px for the entire page.
- However, we want to deduct our windowHeight as

**scrollHeight**

- This is the amount of pixels that we scrolled down from the top of the page. It starts at 0 and can go all the way up to the bottom of the screen (minus page height).
- We get it by calling `window.scrollY`
- For example, if out page is 2000 px long and we scrolled down all the way to the top, this value would be 1500 px (because our window is 500px).

So, you see already what’s going on here:

—> we need to deduct the windowHeight from our pageHeight.

This way, if we scroll down 1500 pixels, the pageHeight is 2000px - 500px = 1500 px, meaning we scrolled down the entire page.

Lastly, we return our percentage by saying `return scrollHeight / pageHeight * 100`

```jsx
// ...
getScrollPercentage() {
        const windowHeight = window.innerHeight;
        const pageHeight = document.body.scrollHeight - windowHeight;
        const scrollHeight = window.scrollY + 1;
        return scrollHeight / pageHeight * 100;
    }
// ...
```

### init()

This is the last step, promised!

As you’ve already seen above, we now call all of the previously defined method inside of our init() method.

This is not necessary, but it makes the code more organized and readable.

So everytime we call this init() method inside of our constructor, all of the methods will get executed and we’re left with… our beautiful scrollbar

```jsx
// ...
init() {
        this.insertParentElement();
        this.insertFillingElement();
        this.addScrollListener();
    }
// ...
```

## 3. Creating a new class instance

All we have to do now is create a new instance of our class and pass in some parameters.

These are the selector for the navbar (here ‘nav.nav’), a position (here ‘beforeend’), a color (here an orange with #71b9f0) and our window object.

```jsx
const scrollIndicator = new ScrollIndicator('nav.nav', 'beforeend', '#71b9f0', window)
```

Et voila…

Just like magic, we now have our scroll indicator inserted right into our navbar.


![Uploading image](...)

## Summary

So, to sum it up.

All you have to do is create this scroll Indicator class (which you can customize any way you want simply by expanding on the code).

When you create a new instance of this class, a new scrollbar is inserted into the specific element (most likely your nav bar).

And… that’s pretty much it!

## Feedback

Since this is my first blog post here, I would be especially happy to hear from you!

What did you think of this class-based solution? Helpful or redundant?

What could be done better? And would you use this in your website?

Any comments are welcome (the good, the bad, the ugly too ;) )!

Have a great day 

Sam