Script Valley
Building Your Developer Portfolio
Adding Interactivity with JavaScriptLesson 3.5

How to add an active nav link highlight based on scroll position

active navigation state, IntersectionObserver for nav, classList add and remove, data attributes, multiple section tracking, nav link selector matching

Highlight the Active Section in the Nav

Highlighting the nav link that matches the currently visible section helps visitors understand where they are on a long page. The cleanest implementation uses a single IntersectionObserver watching all sections.

HTML: Add id and data Attributes

<!-- Nav links use href matching section ids -->
<a href="#projects" data-nav="projects">Projects</a>

<!-- Sections have matching ids -->
<section id="projects">...</section>

JavaScript: Section Observer

const sections = document.querySelectorAll('section[id]');
const navLinks = document.querySelectorAll('[data-nav]');

const sectionObserver = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const id = entry.target.id;
      navLinks.forEach(link => {
        link.classList.toggle(
          'nav-active',
          link.getAttribute('data-nav') === id
        );
      });
    }
  });
}, { threshold: 0.5, rootMargin: '-80px 0px 0px 0px' });

sections.forEach(section => sectionObserver.observe(section));
.nav-active {
  color: #0070f3;
  font-weight: 600;
  border-bottom: 2px solid #0070f3;
}

The rootMargin: '-80px 0px 0px 0px' offsets the observer's root boundary by the navbar height so sections are not marked active before they visually appear below the sticky nav. The threshold: 0.5 means a section must be 50% visible to trigger the active state.

How to add an active nav link highlight based on scroll position — Adding Interactivity with JavaScript — Building Your Developer Portfolio — Script Valley — Script Valley