Changing Active Class in Side Navigation of React Using IntersectionObserver

react sidebar active class intersectionobserver
10 November 2024

In this article, we aim to explore a simple and efficient way to manage active classes in side navigation of a React program using IntersectionObserver. In responsive environments and when creating smart side navigations, one of the primary needs is to identify the user's position on the page. This can help the user understand which part of the page they are on and can enhance the user experience.

One of the interesting and modern solutions to this problem is using the IntersectionObserver API. This API allows us to observe elements continuously and alter their styles accordingly. For example, we could assign a relevant active class to the section of a page currently viewed by the user.

The main capability of the IntersectionObserver is that it can determine whether an element is displayed on the page or not. Therefore, by utilizing this tool, we can manage the visibility of elements without needing to resort to older methods like event listeners based on scroll performance, which can generally lead to increased load and sluggishness of the page.

In this example, we will show how to use IntersectionObserver to dynamically add the active class to the respective side navigation and implement this operation in a real-world project. Thus, you'll see how to easily associate code directly in your project.

Below we will also review a sample of the practical code:

import React, { useEffect, useRef, useState } from 'react';

const Sidebar = () => {
const sections = useRef([]);
const [activeSection, setActiveSection] = useState('');

useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setActiveSection(entry.target.id);
}
});
},
{ threshold: 0.7 }
);

sections.current.forEach((section) => {
observer.observe(section);
});

return () => {
observer.disconnect();
};
}, []);

return (
<div className="sidebar">
<ul>
<li className={activeSection === 'section1' ? 'active' : ''}>Section 1</li>
<li className={activeSection === 'section2' ? 'active' : ''}>Section 2</li>
<li className={activeSection === 'section3' ? 'active' : ''}>Section 3</li>
</ul>
</div>
);
};

export default Sidebar;

Code Clarifications:

import React, { useEffect, useRef, useState } from 'react';

Importing necessary variables from the React library.
const Sidebar = () => {

Defining the Sidebar component.
const sections = useRef([]);

A reference for storing page sections.
const [activeSection, setActiveSection] = useState('');

A state to store the currently active section.
useEffect(() => {

Using useEffect to set up and manage IntersectionObserver.
const observer = new IntersectionObserver((entries) => { ... }, { threshold: 0.7 });

Defining a new observer that watches the elements on the page.
sections.current.forEach((section) => { observer.observe(section); });

Observing all sections on the page.
return () => { observer.disconnect(); };

Disconnecting the observer when leaving the component.
return (<div className="sidebar"> ... </div>);

JSX structure for displaying side navigation.
export default Sidebar;

Exporting the Sidebar component for use in other parts of the app.

FAQ

?

Why do we use IntersectionObserver for changing classes?

?

Can multiple observers be used simultaneously?

?

How can we adjust different thresholds for active class management?