Snippets/react/useScrollProgress Hook
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/UX
reacthooksanimationui

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 window existence to prevent hydration mismatches.
  • Normalized Output: Returns a float between 0.0 and 1.0 for 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 opacity or transform properties for parallax effects!