DEV Community

Thomas Ledoux
Thomas Ledoux

Posted on • Updated on • Originally published at

Highlighting navigation items on scroll in React with IntersectionObserver

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)
Enter fullscreen mode Exit fullscreen mode

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])
Enter fullscreen mode Exit fullscreen mode

And that's it! The active class will be added to the navigation element which points to the <section>.
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

Top comments (0)