diff --git a/README.md b/README.md
index 569c82e26c..494daf12a1 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,8 @@
- [`useMotion`](./docs/useMotion.md) — tracks state of device's motion sensor.
- [`useNetwork`](./docs/useNetwork.md) — tracks state of user's internet connection.
- [`useOrientation`](./docs/useOrientation.md) — tracks state of device's screen orientation.
+ - [`useScroll`](./docs/useScroll.md) — some HTML element's scroll position. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usescroll--docs)
+
- [`useSize`](./docs/useSize.md) — tracks some HTML element's dimensions.
- [`useWindowScroll`](./docs/useWindowScroll.md) — tracks `Window` scroll position. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usewindowscroll--docs)
- [`useWindowSize`](./docs/useWindowSize.md) — tracks `Window` dimensions. [![][img-demo]](https://codesandbox.io/s/m7ln22668)
diff --git a/docs/useScroll.md b/docs/useScroll.md
new file mode 100644
index 0000000000..6de5730795
--- /dev/null
+++ b/docs/useScroll.md
@@ -0,0 +1,21 @@
+# `useScroll`
+
+React sensor hook that re-renders on when scroll position in a DOM element changes.
+
+## Usage
+
+```jsx
+import {useScroll} from 'react-use';
+
+const Demo = () => {
+ const element = React.useRef(null);
+ const {x, y} = useScroll(element);
+
+ return (
+
+ right: 0
+ }}>
x: {x}
y: {y}
diff --git a/src/index.ts b/src/index.ts
index 514af8dbdb..ba0298d64d 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -35,6 +35,7 @@ import useOutsideClick from './useOutsideClick';
import usePromise from './usePromise';
import useRaf from './useRaf';
import useRefMounted from './useRefMounted';
+import useScroll from './useScroll';
import useSessionStorage from './useSessionStorage';
import useSetState from './useSetState';
import useSize from './useSize';
@@ -90,6 +91,7 @@ export {
usePromise,
useRaf,
useRefMounted,
+ useScroll,
useSessionStorage,
useSetState,
useSize,
diff --git a/src/useScroll.ts b/src/useScroll.ts
new file mode 100644
index 0000000000..dcbdc99834
--- /dev/null
+++ b/src/useScroll.ts
@@ -0,0 +1,48 @@
+import {useState, useEffect, useRef} from 'react';
+import {isClient} from './util';
+
+export interface State {
+ x: number;
+ y: number;
+}
+
+const useScroll = (ref): State => {
+ const frame = useRef(0);
+ const [state, setState] = useState
({
+ x: isClient ? window.scrollX : 0,
+ y: isClient ? window.scrollY : 0
+ });
+
+ useEffect(() => {
+ const handler = () => {
+
+ frame.current = requestAnimationFrame(() => {
+ setState({
+ x: ref.current.scrollLeft,
+ y: ref.current.scrollTop
+ });
+ });
+ }
+
+ if (ref && ref.current) {
+ ref.current.addEventListener('scroll', handler, {
+ capture: false,
+ passive: true
+ });
+ }
+
+ return () => {
+ if (frame.current) {
+ cancelAnimationFrame(frame.current);
+ }
+
+ if (ref && ref.current) {
+ ref.current.removeEventListener('scroll', handler);
+ }
+ };
+ }, [ref]);
+
+ return state;
+}
+
+export default useScroll