diff --git a/packages/core/index.ts b/packages/core/index.ts
index 2471ee261956..1657a7b6c78c 100644
--- a/packages/core/index.ts
+++ b/packages/core/index.ts
@@ -49,6 +49,7 @@ export * from './useFps'
export * from './useFullscreen'
export * from './useGeolocation'
export * from './useIdle'
+export * from './useInfiniteScroll'
export * from './useIntersectionObserver'
export * from './useKeyModifier'
export * from './useLocalStorage'
diff --git a/packages/core/useInfiniteScroll/demo.vue b/packages/core/useInfiniteScroll/demo.vue
new file mode 100644
index 000000000000..0be91dd14c5b
--- /dev/null
+++ b/packages/core/useInfiniteScroll/demo.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
diff --git a/packages/core/useInfiniteScroll/index.md b/packages/core/useInfiniteScroll/index.md
new file mode 100644
index 000000000000..f06178b21031
--- /dev/null
+++ b/packages/core/useInfiniteScroll/index.md
@@ -0,0 +1,36 @@
+---
+category: Sensors
+---
+
+# useInfiniteScroll
+
+Infinite scrolling of the element.
+
+## Usage
+
+```html
+
+
+
+
+
+```
diff --git a/packages/core/useInfiniteScroll/index.ts b/packages/core/useInfiniteScroll/index.ts
new file mode 100644
index 000000000000..deeefb2bafda
--- /dev/null
+++ b/packages/core/useInfiniteScroll/index.ts
@@ -0,0 +1,44 @@
+import type { UnwrapNestedRefs } from 'vue-demi'
+import { reactive, watch } from 'vue-demi'
+import type { MaybeRef } from '@vueuse/shared'
+import type { UseScrollOptions } from '../useScroll'
+import { useScroll } from '../useScroll'
+
+export interface UseInfiniteScrollOptions extends UseScrollOptions {
+ /**
+ * The minimum distance between the bottom of the element and the bottom of the viewport
+ *
+ * @default 0
+ */
+ distance?: number
+}
+
+/**
+ * Reactive infinite scroll.
+ *
+ * @see https://vueuse.org/useInfiniteScroll
+ */
+export function useInfiniteScroll(
+ element: MaybeRef,
+ onLoadMore: (state: UnwrapNestedRefs>) => void,
+ options: UseInfiniteScrollOptions = {},
+) {
+ const state = reactive(useScroll(
+ element,
+ {
+ ...options,
+ offset: {
+ bottom: options.distance ?? 0,
+ ...options.offset,
+ },
+ },
+ ))
+
+ watch(
+ () => state.arrivedState.bottom,
+ (v) => {
+ if (v)
+ onLoadMore(state)
+ },
+ )
+}