JSFiddle - React, Tailwind, and code Playground

by Jordan Sayner

HTML

<nav id="progress-nav">
  <ul>
    <li><a href="#bcorp">What is B-Corp?</a></li>
    <li><a href="#renewables">Investing in Renewables</a></li>
    <li><a href="#spaces">Community Spaces</a></li>
    <li><a href="#initiatives">Other Initiatives</a></li>
    <li><a href="#goals">Future Goals</a></li>
    <li><a href="#progress">Our Progress</a></li>
  </ul>
  <div id="progress-line"></div>
</nav>

<!-- Sections -->
<section id="bcorp">...</section>
<section id="renewables">...</section>
<section id="spaces">...</section>
<section id="initiatives">...</section>
<section id="goals">...</section>
<section id="progress">...</section>

CSS

#progress-nav {
  position: fixed;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  width: 80%;
  background: white;
  padding: 10px 20px;
  border-radius: 50px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  z-index: 1000;
}

#progress-nav ul {
  display: flex;
  width: 100%;
  justify-content: space-between;
  position: relative;
}

#progress-nav ul li {
  list-style: none;
  position: relative;
  flex: 1;
  text-align: center;
}

/* Dots */
#progress-nav ul li::before {
  content: "";
  position: absolute;
  bottom: -10px;
  left: 50%;
  transform: translateX(-50%);
  width: 8px;
  height: 8px;
  background: lightgray;
  border-radius: 50%;
  transition: background 0.3s ease;
}

#progress-nav ul li.active::before {
  background: blue;
}

/* Progress Line */
#progress-line {
  
  height: 3px;
  width: 0%;
  background: blue;
  transition: width 0.3s ease;
}

#progress-nav ul li a {
  text-decoration: none;
  color: gray;
  font-size: 14px;
  transition: color 0.3s;
}

#progress-nav ul li.active a {
  color: blue;
  font-weight: bold;
}
section {
  min-height: 150vh;
}

JavaScript

document.addEventListener("DOMContentLoaded", function () {
  const sections = document.querySelectorAll("section");
  const navLinks = document.querySelectorAll("#progress-nav ul li");
  const progressLine = document.getElementById("progress-line");

  function updateProgress() {
    let scrollPosition = window.scrollY;
    let totalHeight = document.body.scrollHeight - window.innerHeight;
    let progressPercentage = (scrollPosition / totalHeight) * 100;

    // Update progress line width
    progressLine.style.width = progressPercentage + "%";

    sections.forEach((section, index) => {
      let top = section.offsetTop - 100; // Adjust for sticky nav
      let bottom = top + section.clientHeight;
      if (scrollPosition >= top && scrollPosition < bottom) {
        navLinks.forEach((link) => link.classList.remove("active"));
        navLinks[index].classList.add("active");
      }
    });
  }

  window.addEventListener("scroll", updateProgress);
  updateProgress(); // Initial call
});