Skip to content
15 changes: 15 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import useDetectScroll, {

The `useDetectScroll` hook takes an options object with the following properties:

- `target`: The target scrollable element from which to detect scroll direction and position (default: `window`, must be an `HTMLDivElement`).
- `thr`: Threshold for scroll direction change detection (default: `0`, accepts only positive values).
- `axis`: Defines the scroll axis (`"y"` or `"x"`, default: `"y"`).
- `scrollUp`: Value returned when scrolling up (y-axis) or left (x-axis) (default: `"up"` for y-axis, `"left"` for x-axis).
Expand Down Expand Up @@ -74,6 +75,20 @@ const { scrollDir, scrollPosition } = useDetectScroll({ axis: Axis.X });
// scrollPosition: { top, bottom, left, right }
```

To use a custom scrollable element as a target rather than the default window:

```js
const customElementRef = useRef<HTMLDivElement>(null);
const [customElement, setCustomElement] = useState<HTMLDivElement>();
useEffect(() => {
if(customElementRef.current) {
setHomepageElement(customElementRef.current);
}
}, [customElementRef])
const scrollDir = useDetectScroll({target: customElement});
console.log(scrollDir);
```

## Contributing

Interested in making contributions to this project? Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines and details.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,5 @@
},
"type": "module",
"types": "./dist/index.d.ts",
"version": "4.1.0"
"version": "4.2.0"
}
62 changes: 49 additions & 13 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ type ScrollInfo = {

/** Type declaration for scroll properties */
type ScrollProps = {
/**
* The target represents the scrollable element to check for scroll detection.
*/
target?: HTMLDivElement | Window;
/**
* The thr represents the threshold value for scroll detection.
*/
Expand Down Expand Up @@ -125,6 +129,7 @@ type ScrollProps = {
*/
function useDetectScroll(props: ScrollProps = {}): ScrollInfo {
const {
target = window,
thr = 0,
axis = Axis.Y,
scrollUp = axis === Axis.Y ? Direction.Up : Direction.Left,
Expand All @@ -146,40 +151,70 @@ function useDetectScroll(props: ScrollProps = {}): ScrollInfo {

/** Function to update scroll direction */
const updateScrollDir = useCallback(() => {
const scroll = axis === Axis.Y ? window.scrollY : window.scrollX;
let scroll: number;
if (target instanceof Window) {
scroll = axis === Axis.Y ? target.scrollY : target.scrollX;
} else {
scroll =
axis === Axis.Y
? (target as HTMLDivElement).scrollTop
: (target as HTMLDivElement).scrollLeft;
}

if (Math.abs(scroll - lastScroll.current) >= threshold) {
setScrollDir(scroll > lastScroll.current ? scrollDown : scrollUp);
lastScroll.current = Math.max(0, scroll);
}
ticking.current = false;
}, [axis, threshold, scrollDown, scrollUp]);
}, [target, axis, threshold, scrollDown, scrollUp]);

useEffect(() => {
/** Function to update scroll position */
const updateScrollPosition = () => {
const top = window.scrollY;
const left = window.scrollX;
const top =
target instanceof Window
? target.scrollY
: (target as HTMLDivElement).scrollTop;
const left =
target instanceof Window
? target.scrollX
: (target as HTMLDivElement).scrollLeft;
const bottom =
document.documentElement.scrollHeight - window.innerHeight - top;
document.documentElement.scrollHeight -
(target instanceof Window
? target.innerHeight
: (target as HTMLDivElement).scrollHeight) -
top;
const right =
document.documentElement.scrollWidth - window.innerWidth - left;
document.documentElement.scrollWidth -
(target instanceof Window
? target.innerWidth
: (target as HTMLDivElement).scrollWidth) -
left;

setScrollPosition({ top, bottom, left, right });
};

/** Call the update function when the component mounts */
updateScrollPosition();

window.addEventListener('scroll', updateScrollPosition);
const targetElement = target as EventTarget;
targetElement.addEventListener('scroll', updateScrollPosition);

return () => {
window.removeEventListener('scroll', updateScrollPosition);
targetElement.removeEventListener('scroll', updateScrollPosition);
};
}, []);
}, [target]);

useEffect(() => {
lastScroll.current = axis === Axis.Y ? window.scrollY : window.scrollX;
if (target instanceof Window) {
lastScroll.current = axis === Axis.Y ? target.scrollY : target.scrollX;
} else {
lastScroll.current =
axis === Axis.Y
? (target as HTMLDivElement).scrollTop
: (target as HTMLDivElement).scrollLeft;
}

/** Function to handle onScroll event */
const onScroll = () => {
Expand All @@ -189,10 +224,11 @@ function useDetectScroll(props: ScrollProps = {}): ScrollInfo {
}
};

window.addEventListener('scroll', onScroll);
const targetElement = target as EventTarget;
targetElement.addEventListener('scroll', onScroll);

return () => window.removeEventListener('scroll', onScroll);
}, [axis, updateScrollDir]);
return () => targetElement.removeEventListener('scroll', onScroll);
}, [target, axis, updateScrollDir]);

return { scrollDir, scrollPosition };
}
Expand Down
Loading