All hooks / Elements

useElementScroll

451 B minified and brotliedSourceMarkdown✓ Works in all modern browsers

The scroll position of a scrollable element, and whether it is at each edge. Returns a callback ref for the element.

Updates on scroll, and also when the element or its content changes size with no scroll event (rows added, text streamed in), so atBottom never goes stale. Before the element is measured, and on the server, it is at 0, 0 with every edge true.

Re-renders as x and y change, about once a frame while scrolling. If an expensive component only needs the edge flags, call the hook in a small child component instead.

Import

import { useElementScroll } from '@vincent.ri/react-tils'
// or only this hook
import { useElementScroll } from '@vincent.ri/react-tils/useElementScroll'

Usage

const [ref, { atTop, atBottom }] = useElementScroll<HTMLDivElement>()
return (
  <div ref={ref} style={{ overflow: 'auto', maxHeight: 400 }}
    className={[!atTop && 'shadow-top', !atBottom && 'shadow-bottom'].filter(Boolean).join(' ')}>
    <Rows />
  </div>
)

Live demo

Scroll the list: shadows show where there is more.

Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12
Row 13
Row 14
Row 15
Row 16
Row 17
Row 18
Row 19
Row 20
Row 21
Row 22
Row 23
Row 24
Row 25
Row 26
Row 27
Row 28
Row 29
Row 30
y 0 · top yes · bottom yes

When to use it

Fade shadows at the edges of a scrolling table or list, a "scroll to top" button inside a panel, or "you've read to the end" in a container.

When not to

The page itself scrolls; use useWindowScroll. For a chat that follows new messages, use useStickToBottom. Shadows alone can be done with CSS scroll-driven animations where supported.

API

function useElementScroll<T extends Element = HTMLElement>(): [(element: T | null) => void, ElementScroll]

Returns [ref, scroll]. Pass ref to the scrollable element.

Types

export type ElementScroll = {
  /** `scrollLeft`: 0 or negative in right-to-left content, as in the DOM. */
  x: number;
  /** `scrollTop`. */
  y: number;
  atTop: boolean;
  atBottom: boolean;
  atLeft: boolean;
  atRight: boolean;
};

Browser support

UsesChromeEdgeFirefoxSafariChrome AndroidSafari iOS
ResizeObserverWidely available64+79+69+13.1+64+13.4+
MutationObserverWidely available26+12+14+7+26+7+

First version with support, from MDN's compatibility data (web-features 3.42.0, @mdn/browser-compat-data 8.1.5).

Coming from another library?

Other libraries call this useScroll.