Skip to content

useWindowScroll

Tracks the window scroll position, direction, arrived state, and scrolling status as reactive Observable values. A convenience wrapper around useScroll(window).

x: 0y: 0idle
topbottomleftright

Scroll the page to see the values update in real time.

import {
import useWindowScroll
useWindowScroll
} from "@usels/core";
function
function Component(): React.JSX.Element
Component
() {
const {
const x: any
x
,
const y: any
y
,
const arrivedState: any
arrivedState
} =
import useWindowScroll
useWindowScroll
();
return (
<
React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
scrollX: {
const x: any
x
.
any
get
()}, scrollY: {
const y: any
y
.
any
get
()}
{
const arrivedState: any
arrivedState
.
any
bottom
.
any
get
() && " — reached bottom"}
</
React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
);
}
import {
import useWindowScroll
useWindowScroll
} from "@usels/core";
function
function BackToTop(): React.JSX.Element | null
BackToTop
() {
const {
const arrivedState: any
arrivedState
} =
import useWindowScroll
useWindowScroll
();
return !
const arrivedState: any
arrivedState
.
any
top
.
any
get
() ? (
<
React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick
={() =>
any
window
.
any
scrollTo
({
top: number
top
: 0,
behavior: string
behavior
: "smooth" })}>↑ Back to top</
React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
) : null;
}
const { directions } = useWindowScroll();
// directions.bottom.get() → true while scrolling down
// directions.top.get() → true while scrolling up
import { useObserveEffect } from "@legendapp/state/react";
const { arrivedState } = useWindowScroll({ offset: { bottom: 200 } });
useObserveEffect(arrivedState.bottom, (e) => {
if (e.value) fetchNextPage();
});
const { isScrolling } = useWindowScroll({
idle: 300,
onStop: () => saveScrollPosition(),
});
const { y } = useWindowScroll({ throttle: 100 });

SSR-safe. When window is not available (SSR), useWindowScroll passes null to useScroll, so all observables hold initial values (x: 0, y: 0, isScrolling: false) and no event listener is registered.

See useScroll for the full API reference including all options.

export type { UseScrollOptions, UseScrollReturn };
export declare function useWindowScroll(options?: UseScrollOptions): UseScrollReturn;

View on GitHub

  • tigerwest
  • a7392ab 2026-03-06 - feat(core,browser): add sync strategy hooks (tigerwest)