Scrolling up · bottom of page in view: no

All hooks / Viewport and media

useScrollSpy

266 B minified and brotliedSourceMarkdown✓ Works in all modern browsers

The id of the section the user is reading: the last of ids whose element has scrolled past the top of the viewport (plus offset). At the bottom of the page the last section is active, even if it is too short to reach the top. null before the first section, on the server, and during hydration.

Re-renders only when the active section changes. Sections are looked up by id on each scroll, so they can mount later.

Import

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

Usage

const ids = ['install', 'usage', 'api']
const active = useScrollSpy(ids, { offset: 64 })
return (
  <nav>
    {ids.map((id) => (
      <a key={id} href={`#${id}`} aria-current={active === id ? 'location' : undefined}>{id}</a>
    ))}
  </nav>
)

Live demo

Scroll the page: the sidebar highlights the section you're reading.

reading: —

When to use it

Highlighting the current section in a table of contents, a docs sidebar, or step navigation on a long page.

When not to

The sections scroll inside a container rather than the page; this follows the window. To know whether one element is on screen, use useInView.

API

function useScrollSpy(ids: readonly string[], options?: ScrollSpyOptions): string | null
ParameterDescription
idsElement ids of the sections, in page order.
optionsoffset: height of a sticky header in pixels. Optional.

Returns The active id, or null.

Types

export type ScrollSpyOptions = {
  /** Distance in pixels from the top of the viewport to the line a section must cross to become active, e.g. a sticky header's height. Default `0`. */
  offset?: number;
};

Browser support

Uses only long-established browser features, so it works wherever React does.

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 useActiveSection, useScrollspy.