Skip to content
All writing

Create a React Progress Bar Component

A reusable React reading progress bar (scroll progress indicator) with SCSS modules that only starts filling once the article reaches the top of the screen.

#snippetsreactcssjavascript

Yes, it's that thin bar that fills up as you scroll through an article. It was on kimdontdoit when I wrote this. It's also called a scroll progress indicator, and it's a small UX bonus for readers.

Here's a React component for it that you can reuse and adapt.

import React, { useState, useEffect } from "react";
import * as classes from "./ScrollProgress.module.scss";

const ScrollProgress = ({ target }) => {
	const [readingProgress, setReadingProgress] = useState(0);

	const scrollListener = () => {
		if (!target.current) {
			return;
		}

		const element = target.current;

		const windowScrollTop =
			window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;

		if (windowScrollTop <= element.offsetTop) {
			setReadingProgress(0);
		} else {
			setReadingProgress(
				((windowScrollTop - element.offsetTop) /
					(element.clientHeight - element.offsetTop - window.innerHeight)) *
					100,
			);
		}
	};

	useEffect(() => {
		window.addEventListener("scroll", scrollListener);
		return () => window.removeEventListener("scroll", scrollListener);
	});

	return (
		<div className={classes.progressContainer}>
			<div className={classes.progress} style={{ width: `${readingProgress}%` }} />
		</div>
	);
};

export { ScrollProgress };

The target prop is a ref to the article element. Progress stays at 0 until that element reaches the top of the viewport (see windowScrollTop), so a header or hero image above the article doesn't count as reading.

Get new posts by email

New writing in your inbox. Unsubscribe anytime.