photo ScrollToggle in JavaScript

Want to change a navbar’s appearance? ScrollToggle—an optimized JavaScript solution


Introduction

Have you ever wanted to change the appearance of a navbar when a user scrolls down the page? Maybe add a shadow, change the background color, or make the navbar sticky? Instead of writing repetitive event listeners, let's create a reusable JavaScript class that handles scroll-based UI changes efficiently.

In this post, we’ll introduce ScrollToggle, a JavaScript class that dynamically toggles CSS classes when a user scrolls past a defined point.


Why Use a Scroll-Based Class?

Manually adding an event listener for scrolling can be inefficient and cause performance issues. Without proper optimization, the browser might trigger hundreds of scroll events per second, making the page sluggish.

With ScrollToggle, we: ✅ Use requestAnimationFrame() to optimize performance.
✅ Prevent unnecessary function calls using throttling.
✅ Keep our code reusable and modular for future projects.


Building the ScrollToggle Class

Here’s how we define the class:

class ScrollToggle {
  constructor(selector, options = {}) {
    this.element = document.querySelector(selector);
    if (!this.element) return;

    this.config = {
      limit: options.limit || 50,
      backgroundOn: options.backgroundOn || 400,
      classNames: options.classNames || ['bg-body-tertiary', 'shadow'],
    };

    this.lastCall = 0;
    this.frameRequest = null;

    this.handleScroll = this.throttleRAF(this.handleScroll.bind(this));
    window.addEventListener('scroll', this.handleScroll);
  }

  throttleRAF(func) {
    return (...args) => {
      const now = Date.now();
      if (now - this.lastCall >= this.config.limit) {
        if (this.frameRequest) cancelAnimationFrame(this.frameRequest);
        this.frameRequest = requestAnimationFrame(() => {
          this.lastCall = now;
          func.apply(this, args);
        });
      }
    };
  }

  handleScroll() {
    const shouldChange = window.scrollY > this.config.backgroundOn;
    const hasAnyClass = this.config.classNames.some((cls) =>
      this.element.classList.contains(cls)
    );

    if (shouldChange !== hasAnyClass) {
      this.config.classNames.forEach((cls) => {
        this.element.classList.toggle(cls, shouldChange);
      });
    }
  }
}

How It Works

  1. The constructor sets up the element and scroll threshold.
  2. The throttle function prevents excessive function calls.
  3. The handleScroll() function checks the scroll position and toggles classes accordingly.

Using ScrollToggle

Simply attach it to a navbar:

const navbarScrollEffect = new ScrollToggle('.navbar', {
  backgroundOn: 400,
  limit: 80,
  classNames: ['bg-body-tertiary', 'shadow'],
});

This will:

  • Add the classes bg-body-tertiary shadow when scrolled past 400px.
  • Remove them when scrolled back up.

Why This Approach?

✅ Performance Optimized – Uses requestAnimationFrame() to reduce lag.
✅ Reusable – Works on any element, not just navbars.
✅ Customizable – Set your own class names and scroll threshold.


Conclusion

With ScrollToggle, you can enhance your UI without worrying about performance bottlenecks. Whether it's a sticky navbar, fade-in animations, or other scroll-based effects, this reusable class makes your code cleaner and more efficient.

Try it out and improve your website’s scrolling experience! 

Go back