beginnerreact
useScrollProgress Hook
A simple React hook to track scroll progress (0-100%). Ideal for reading progress bars and parallax effects.
Published December 2, 2025
Updated December 2, 2025
UI/UXreacthooksanimationui
useScrollProgress Hook
This hook tracks the vertical scroll position of the page and returns a normalized value between 0 and 1 (or 0% to 100%). It's commonly used for "Reading Progress" bars at the top of blog posts or for triggering scroll-linked animations.
Highlights
- Lightweight: Uses a passive event listener for better scrolling performance.
- SSR Safe: Checks for
windowexistence to prevent hydration mismatches. - Normalized Output: Returns a float between
0.0and1.0for easy CSS scaling.
Code
import { useEffect, useState } from 'react';
export function useScrollProgress() {
const [progress, setProgress] = useState(0);
useEffect(() => {
const updateProgress = () => {
const currentScroll = window.scrollY;
const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;
if (scrollHeight) {
setProgress(Number((currentScroll / scrollHeight).toFixed(2)));
}
};
window.addEventListener('scroll', updateProgress, { passive: true });
updateProgress(); // Initial check
return () => window.removeEventListener('scroll', updateProgress);
}, []);
return progress;
}Usage
Here is how to build a Reading Progress Bar that sticks to the top of the screen:
import { useScrollProgress } from '@/hooks/useScrollProgress';
export function ReadingProgressBar() {
const progress = useScrollProgress();
return (
<div className="fixed top-0 left-0 h-1 w-full bg-transparent z-50">
<div
className="h-full bg-cyan-500 transition-all duration-150 ease-out"
style={{ width: `${progress * 100}%` }}
/>
</div>
);
}💡 Tip: You can also use this value to drive
opacityortransformproperties for parallax effects!