S
crollTrackingGroup

React component that detects if a 'Section' overlaps with a 'Window'
View on Github
React
TypeScript

About

This component is used in this very portfolio to highlight the current section in the top bar!
This component tracks the overlapping section within the window as the user scrolls through the children sections. It supports both horizontal and vertical scrolling and provides customizable options for window dimensions and offset.

Snippets

1
/* ----------------------------- Scroll Tracking ---------------------------- */
2
useScrollPosition(
3
({ currPos }) => {
4
if (sections.current && wind.current) {
5
const axis = orientation === "vertical" ? "y" : "x";
6
const axisEnd = orientation === "vertical" ? "bottom" : "right";
7
const s = sections.current;
8
let topMost: (SectionObj & { id: string }) | undefined;
9
10
const wRect = currPos;
11
const offset = {
12
top: orientation === "vertical" ? wRect.top : wRect.left,
13
btm: orientation === "vertical" ? wRect.bottom : wRect.right,
14
};
15
Object.entries(s).forEach(([id, section]) => {
16
if (section) {
17
const pos = section.position;
18
19
if (
20
doesOverlap(
21
{ start: offset.top, end: offset.btm },
22
{ start: pos[axis], end: pos[axisEnd] }
23
)
24
) {
25
// If this section's position is further up the page than current topMost section
26
// or if topMost hasn't been set, set this section as topMost.
27
if (
28
(topMost &&
29
(!flipped
30
? pos[axis] < topMost.position[axis]
31
: pos[axis] > topMost.position[axis])) ||
32
!topMost
33
) {
34
topMost = { id, ...section };
35
}
36
}
37
}
38
});
39
40
if (topMost) setScrolledTo([topMost.id, topMost.element]);
41
}
42
},
43
[wind, flipped, orientation, lastUpdated],
44
wind,
45
undefined,
46
undefined,
47
localScroll ? container : undefined
48
);
Here we use the 'useScrollPosition' hook to track the window's scroll position via 'currPos'. Depending on the component's 'orientation' property, we set the 'axis' and 'axisEnd' values accordingly to handle both vertical and horizontal scrolling. Then we iterate through the sections and run 'doesOverlap' to check if the section overlaps with the window. If it does, it checks against the current 'topMost', and if it's higher, it becomes the 'topMost'. Finally, we call 'setScrolledTo' with the section's ID and element ref.