Skip to main content

Scroll & Position

Hooks that track where the window or an element is — scroll offset, bounding rect, viewport size, or breakpoint.

useWindowScroll

Tracks the window scroll position (x/y) and progress (%) in real time. Try scrolling this page!

scrollY: 0px (0%)
scrollX: 0px (0%)

Extra content below so you can see the values actually move as you scroll.

const { x, y, percent } = useWindowScroll();

useElementScroll

Tracks a scroll container's position, percentage, and whether it's at the top or bottom.

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12
Item 13
Item 14
Item 15
Item 16
Item 17
Item 18
Item 19
Item 20
Scroll progress: 0%
At top: Y / At bottom: N
const { setRef, scrollPercentage, isAtTop, isAtBottom } = useElementScroll();

<div ref={setRef}>...scrollable content...</div>;

useElementPosition

Tracks an element's getBoundingClientRect in real time as you scroll or resize.

Tracked box
top: - / left: -
width: - / height: -

Try scrolling the page or resizing the window.

const ref = useRef<HTMLDivElement>(null);
const rect = useElementPosition(ref);

useResponsiveSize

Observes an element's size and reports the current breakpoint (xs–2xl). Useful as a container-query alternative.

Current breakpoint: xs
Size: 0 x 0

Drag the bottom-right corner of the box to resize it.

const { size, breakpoint, ref } = useResponsiveSize<HTMLDivElement>();

<div ref={ref}>Current breakpoint: {breakpoint.current}</div>;

useViewport

Tracks the actual visible viewport size, offset, and scale via visualViewport. Useful for handling mobile keyboards and pinch-zoom.

width: 0 / height: 0
scale: 1.00

Pinch-zoom or open the keyboard on mobile to see the values change.

const viewport = useViewport();

useScrollToElements

Smoothly scrolls to elements registered by key.

Section 1 content
Section 2 content
Section 3 content
const { register, scrollTo } = useScrollToElements({ offset: 16 });

<div ref={register('section-1')}>...</div>
<button onClick={() => scrollTo('section-1')}>Go</button>

useBodyScrollLock

Locks the body scroll behind a modal or drawer while it's open.

const [open, setOpen] = useState(false);

useBodyScrollLock(open);
useKeyPress('esc', () => setOpen(false), { enabled: open });