Skip to content

useScrollProgress

ts
useScrollProgress(target: Element, options?: { offset?: string }): Service<ScrollProgressProps>

An element's progress through the viewport as it scrolls.

Props

ts
interface ScrollProgressProps {
  readonly startX: number;
  readonly startY: number;
  readonly endX: number;
  readonly endY: number;
  readonly currentX: number;
  readonly currentY: number;
  readonly progressX: number;
  readonly progressY: number;
}

start and end are the scroll positions at which the progress is 0 and 1; current is where the scroller is now.

Usage

js
import { 
Base
,
useScrollProgress
} from '@studiometa/js-toolkit';
class
Parallax
extends
Base
{
static
config
= {
name
: 'Parallax' };
mounted
() {
return
useScrollProgress
(this.
$el
).
subscribe
(({
progressY
}) => {
this.
$el
.
style
.
setProperty
('--progress',
String
(
progressY
));
}); } }

The offset option

One string holding two edge pairs, separated by a /:

"<target> <viewport> / <target> <viewport>"

The first pair is where the progress is 0, the second where it is 1. In each pair, the first token is an edge of the target and the second an edge of the viewport.

The default is:

js
useScrollProgress(el, { offset: 'start end / end start' });

which reads as "0 when the target's start meets the viewport's end, 1 when the target's end meets the viewport's start" — the element travelling the full height of the viewport.

Each token is one of:

TokenMeans
startthe leading edge
centerthe middle
endthe trailing edge
50%a fraction of the box
120pxan absolute offset from the edge
20vh, 10vw, 5vmin, 5vmaxa viewport unit
a numbera fraction, as 0.5

A token that parses as nothing falls back to the edge.

The resolved offset is part of the service's key, so two callers asking for the same range on the same element share one service.

Mixin

js
class Parallax extends withScrollProgress(Base, { offset: 'center end / center start' }) {
  scrolledInView({ progressY }) {}
}

The hook is named scrolledInView.

Smoothing a progress value

Progress props carry no frame delta, and damp() takes the elapsed time as a required argument — decay is expressed in time, not in frames. So either take the delta from a useRaf() tick, or use smoothTo(), which owns its own frame subscription and releases it when the value arrives.

MIT Licensed