An ambitious light-weight react module written in TypeScript for tracking scroll progress in a performant way. Developed for use with spring based animation libraries such as react-spring, but can be used with or without any library.
Live demo: https://olarsson.github.io/react-scrollsy-examples/
Code examples: https://github.com/olarsson/react-scrollsy-examples/tree/master/src
npm i react-scrollsy
Here is a very basic example that tracks the scroll progress of the document.
import { ScrollTrackerDocument, ScrollTracker } from "react-scrollsy";
import { IScrollData, IScrollObject } from "react-scrollsy/dist/types";
import { useRef } from "react";
function App() {
const refPageProgress = useRef(null);
return (
<ScrollTrackerDocument scrollThrottle={33}> // 1000 ms/30 fps = 33ms, limits the triggered events to 30 fps, optional
{({ scrollData }: IScrollData) => {
return (
<ScrollTracker
scrollData={scrollData}
elem={refPageProgress}
settings={{
duration: {
distance: 100,
unit: "%",
basedOn: "doc",
},
}}>
{({ scrollObject }: IScrollObject) => {
return <h1 ref={refPageProgress}>Here is the scroll progress: {scrollObject.progress}</h1>;
}}
</ScrollTracker>
);
}}
</ScrollTrackerDocument>
);
}
export default App;
Sets the document as the main scrolling container. This or ScrollTrackerCustom must always be the parent of a ScrollTracker component.
Configuration and properties:
scrollThrottle
- (number) throttles the recalculations in ms to this value when the document is scrolled.resizeThrottle
- (number) throttles the recalculations in ms to this value when the document is resized.
Creates a function which returns a scrollData
object as such:
scrollData
- (object, immutable) data returned from the component.scrollTop
- (number, px) the scroll position from the top.containerHeight
- (number, px) height of the container.element
- (number, px) the tracked element for scrolling (document).percentProgress
- (number, %) scroll progress in percent expressed as a number between 0 to 1.scrollHeight
- (number, px) the total scrollable height of the document.
<ScrollTrackerDocument>
{({ scrollData }: IScrollData) => {
return (
// ScrollTracker components and other components can go inside here
);
}}
</ScrollTrackerDocument>
Sets a custom element as the main scrolling container. This or ScrollTrackerDocument must always be the parent of a ScrollTracker component.
Configuration and properties:
scrollThrottle
- (number) throttles the recalculations to this value in ms when the element is scrolled.resizeThrottle
- (number) throttles the recalculations to this value in ms when the element is resized.scrollingElement
- (string, required) the selector for the main scrollable element to track scroll progress of.
Creates a function which returns a scrollData
object as such:
scrollData
- (object, immutable) data returned from the component.scrollTop
- (number, px) the scroll position from the top.containerHeight
- (number, px) height of the container.element
- (number, px) the tracked element for scrolling (custom element).percentProgress
- (number, %) scroll progress in percent expressed as a number between 0 to 1.scrollHeight
- (number, px) the total scrollable height of the document.
<ScrollTrackerCustom
key={active.toString()} // forces a rerender of the tracker, use this if you for example hide the element with 'display: none'
scrollingElement='#custom-scroll-container'>
{({ scrollData }: IScrollData) => {
return (
// ScrollTracker components and other components can go inside here
);
}}
</ScrollTrackerCustom>
A specific DOM element and its progress based on its duration and offsets will be managed by this component.
Configuration and properties:
elem
- (ref, required) sets the element reference to use when tracking scroll progress.settings
- (object, required)duration
- (object, required)distance
- (number, required) how long of the tracked elements duration calculations should be active for.unit
- (['px' | '%'], required) unit the distance should be measured in.basedOn
- (['doc' | 'elem' | 'vp'], required) the duration will be calculated based on distance + unit and what you chose here. 'doc' is the document, 'elem' is the element, 'vp' is the viewport height.
offsetTop
- (object, optional)...
- same props as the duration.
offsetBottom
- (object, optional)...
- same props as the duration.
onStart
- (function, optional) callback to run when scroll progress begins.onEnd
- (function, optional) callback to run when scroll progress ends.
Creates a function which returns a scrollObject
object as such:
scrollObject
(object, immutable) - data returned from the component.scrollData
- (object, immutable) inherited from the main component.progress
- (number, %) scroll progress in percent expressed as a number between 0 to 1.start
- (number, px) the start position in pixels when scroll progress calculation should begin.end
- (number, px) the end position in pixels when scroll progress calculation should end.
<ScrollTracker
scrollData={scrollData} // the scrollData object returned by either ScrollTrackerDocument or ScrollTrackerCustom
elem={refElem}
settings={{
duration: {
distance: 100,
unit: "%",
basedOn: "elem",
},
offsetTop: {
distance: 25,
unit: "%",
basedOn: "vp",
},
offsetBottom: {
distance: -200,
unit: "px",
basedOn: "", // when using px this can be left empty
},
}}>
{({ scrollObject }: IScrollObject) => {
return (
// return for example the scrollObject.progress to reflect progress, and any other elements/components that you wish
)
}}
</ScrollTracker>
- You can now throttle the scrolling events
- resizeThrottle is no longer required
- Initial release
- Write (more) tests
- Refactor the ScrollTrackerCustom?