Skip to content
File

Blob: src/client/hooks/use-scroll-visibility.ts

typescript35 lines
1import { useEffect, useState, useRef } from "react";
2 
3/**
4 * Tracks whether a header/element should be visible based on scroll direction
5 * within a given scroll container (not the window).
6 */
7export function useScrollVisibility(scrollElementId: string, threshold = 5, minOverflow = 80): boolean {
8 const [visible, setVisible] = useState(true);
9 const lastScrollY = useRef(0);
10 
11 useEffect(() => {
12 const el = document.getElementById(scrollElementId);
13 if (!el) return;
14 
15 function onScroll() {
16 const currentY = el!.scrollTop;
17 if (currentY < 10) {
18 setVisible(true);
19 } else if (currentY > lastScrollY.current + threshold) {
20 // Hiding grows the scroll container by the header height; if overflow
21 // is shallow, that collapses the scroll and loops visible/hidden.
22 if (el!.scrollHeight - el!.clientHeight > minOverflow) {
23 setVisible(false);
24 }
25 }
26 lastScrollY.current = currentY;
27 }
28 
29 el.addEventListener("scroll", onScroll, { passive: true });
30 return () => el.removeEventListener("scroll", onScroll);
31 }, [scrollElementId, threshold, minOverflow]);
32 
33 return visible;
34}