VayuUI

useScrollPosition

A hook to track scroll position, direction, progress, and boundary detection.

The useScrollPosition hook tracks the scroll position of the window or a specific element, providing direction, progress percentage, and boundary detection — all throttled for performance.

Demo

Scroll Position

Scroll Y0px
Progress0%
Direction— Idle
Position🔝 Top

Scroll this page to see values update in real-time.

Source Code

Copy this code into src/hooks/useScrollPosition.ts:

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

export interface ScrollPosition {
  x: number;
  y: number;
  directionY: 'up' | 'down' | null;
  directionX: 'left' | 'right' | null;
  isAtTop: boolean;
  isAtBottom: boolean;
  progress: number; // 0–100
}

export const useScrollPosition = (options?: {
  throttle?: number;
  element?: React.RefObject<HTMLElement | null>;
}): ScrollPosition => {
  const { throttle: throttleMs = 50, element } = options ?? {};
  const [position, setPosition] = useState<ScrollPosition>({
    x: 0,
    y: 0,
    directionY: null,
    directionX: null,
    isAtTop: true,
    isAtBottom: false,
    progress: 0,
  });

  // ... throttled scroll handler with rAF
  // See full source for implementation

  return position;
};

Usage

import { useScrollPosition } from '@/hooks/useScrollPosition';

const ScrollIndicator = () => {
  const { progress, directionY, isAtBottom } = useScrollPosition();

  return (
    <div>
      <div style={{ width: `${progress}%` }} className="h-1 bg-blue-500" />
      {isAtBottom && <p>You've reached the bottom!</p>}
    </div>
  );
};

API Reference

Options

PropertyTypeDefaultDescription
throttlenumber50Throttle interval in milliseconds
elementRefObject<HTMLElement>windowElement to track scroll on

Return Value

PropertyTypeDescription
xnumberHorizontal scroll position in pixels
ynumberVertical scroll position in pixels
directionY"up" | "down" | nullVertical scroll direction
directionX"left" | "right" | nullHorizontal scroll direction
isAtTopbooleanWhether scrolled to the top
isAtBottombooleanWhether scrolled to the bottom
progressnumberScroll progress from 0 to 100

On this page