use-scroll-active.ts1.3 KBView on GitHub 'use client';
import { useEffect, useRef, useState } from 'react';
/**
* True while the element is actively being scrolled, false ~`idleMs` after it stops.
*
* Used to show a scrollbar only during scrolling. `scrollbar-width: none` can't do this on its
* own — it hides the bar permanently — and the OS "always show scrollbars" setting overrides the
* usual overlay behaviour, so the visibility has to be driven explicitly.
*
* Returns a ref to attach to the scroll container plus the current state:
*
* const { ref, scrolling } = useScrollActive();
* <div ref={ref} className={cn('overflow-x-auto', scrolling ? 'scrollbar-thin' : 'scrollbar-none')} />
*/
export function useScrollActive<T extends HTMLElement = HTMLDivElement>(idleMs = 800) {
const ref = useRef<T | null>(null);
const [scrolling, setScrolling] = useState(false);
useEffect(() => {
const el = ref.current;
if (!el) return;
let timer: ReturnType<typeof setTimeout> | undefined;
const onScroll = () => {
setScrolling(true);
if (timer) clearTimeout(timer);
timer = setTimeout(() => setScrolling(false), idleMs);
};
el.addEventListener('scroll', onScroll, { passive: true });
return () => {
el.removeEventListener('scroll', onScroll);
if (timer) clearTimeout(timer);
};
}, [idleMs]);
return { ref, scrolling };
}