April 1, 2021

useScrollThreshold: A hook to tell whether you’ve scrolled past a certain point

Often I need to know whether a user has scrolled past a certain pixel threshold value, for example to affix a header, or hide/show some elements. There is of course react-intersection-observer, but often that feels overblown and sometimes I just don't want to add another external dependency. For these cases I created this tiny hook:

import React from 'react'

export const useScrollThreshold = threshold => {
  const [isScrolled, setIsScrolled] = React.useState(false)

  const handleScroll = React.useCallback(() => {
    const scrollTop = window.pageYOffset ?? document.documentElement.scrollTop
    if (scrollTop > threshold && !isScrolled) {
      setIsScrolled(true)
    }
    if (scrollTop <= threshold && isScrolled) {
      setIsScrolled(false)
    }
  }, [isScrolled, threshold])

  React.useEffect(() => {
    window.addEventListener('scroll', handleScroll, { passive: true })
    return () => {
      window.removeEventListener('scroll', handleScroll)
    }
  }, [handleScroll])

  return isScrolled
}

Usage is as easy as:

const hasScrolledPast = useScrollThreshold(72)