Back to overview

Highlighting navigation items on scroll in React with IntersectionObserver

|2 min read

This week I was working on my personal website (, and I needed my navigation items to be highlighted when scrolling to the linked section. I found some solutions with a scroll listener, but none using the widely supported Intersection Observer (

So I decided to write the logic myself. What has to be done first, is referencing the <section>’s using React.useRef.

import * as React from "react";
const personalRef = React.useRef(null);
const portfolioRef = React.useRef(null);
const contactRef = React.useRef(null);

Now we have the reference to the <section>’s we can fire up the IntersectionObserver. I prefer to do this using the React.useEffect hook. The ref objects are added as dependencies, so we can reference these when they are ready. I use the 0.5 threshold, this will cause the observer to be triggered when the <section> is >50% visible. The navElement gets the navigation element which has a href pointing to the <section>’s id.

React.useEffect(() => {
  let observer;
  if (personalRef.current && portfolioRef.current && contactRef.current) {
    const options = {
      threshold: 0.5,
    observer = new IntersectionObserver((entries, observer) => {
      entries.forEach((entry) => {
        const navElement = document.querySelector(
        if (entry.isIntersecting) {
          if (!navElement.classList.contains("active")) {
        } else if (navElement.classList.contains("active")) {
    }, options);
  return () => observer.disconnect();
}, [personalRef, portfolioRef, contactRef]);

And that’s it! The active class will be added to the navigation element which points to the <>. By adding the return function at the end of the useEffect hook, we make sure the IntersectionObserver is cleaned up correctly.

Full code can be found on

Did you like this post? Check out my latest blog posts:

Chrome logo repeated in a grid
4 Sept 2023

Developing a Chrome extension to convert the current url to localhost in 1 click

  • javascript
  • chrome extension
  • html
TailwindCSS logo
12 Jul 2023

Setting and using CSS variables in Tailwind with React

  • css
  • tailwind
  • react
The word update spelled out with scrabble blocks
10 Jul 2023

Keeping your dependencies up to date in a visual way using npm-check-updates

  • javascript
  • nodejs