Track Grouped Sections

To tell a story that spans multiple sections, for example, changing the background based on the section in view, multiple sections tracking tools of react-scrollytelling can help you achieve this.

Instead of tracking every section individually and listening to window scroll events in each section, react-scrollytelling only tracks the sections that are viewport to minimize the performance impact.

Building a scrollytelling story with multiple sections

Here are some key concepts to keep in mind when building a scrollytelling story with multiple sections:

Active section

When there are multiple sections in the viewport, the effects to show should be based on the section that the user is currently viewing.

We call the section the user is currently viewing the "active section", and it the section that has just been scrolled into view. Therefore, the active section is the section that is closest to the bottom of the viewport.

Alt Text

Scroll progress

For the reading/scroll progress of the active section, it is defined as the height above the bottom of the viewport divided by the height of the active section.

Alt Text

Start tracking the active section

1. Set up sections to track

For each section you want to track, assign it with a ref and name it with a unique sectionID. Then, use the useTrackedSectionScroll hook to track the active section based on the sectionID.

import { useTrackedSectionScroll } from '@react-scrollytelling/grouped';
 
export const TrackedSection = ({sectionID} : {sectionID: string}) => {
  const sectionRef = useRef<HTMLDivElement>(null);
  useTrackedSectionScroll(sectionRef, sectionID);
 
  return (
    <section ref={sectionRef}>
      {/* ... */}
    </section>
  );
};

2. Wrap the sections with ScrollytellingProvider

import { ScrollytellingProvider } from '@react-scrollytelling/grouped';
 
// ...
  <ScrollytellingProvider>
    <TrackedSection sectionID="RED" />
    <TrackedSection sectionID="ORANGE" />
  </ScrollytellingProvider>

It is recommended to wrap the sections with one ScrollytellingProvider at the page level because ScrollytellingProvider is listening to the window scroll events.

3. Subscribe to the active section changes

To get the active section information, use the useActiveSection() hook.

import { useActiveSection } from '@react-scrollytelling/grouped';
 
export const ActiveSectionInfo = () => {
  const [trackingId, setTrackingId] = useState<string>('');
  const [scrolledRatio, setScrolledRatio] = useState<number>(0);
 
  const onActiveSectionChange = useCallback(
    ({ trackingId: id, scrolledRatio: ratio }: { trackingId: string; scrolledRatio: number }) => {
      setTrackingId(id);
      setScrolledRatio(ratio);
    },
    []
  );
 
  useActiveSection(onActiveSectionChange);
 
  return (
      <div className="list-disc text-xl leading-9 marker:text-slate-400">
        <ul>
          <li>You are viewing {trackingId}</li>
          <li>Reading ratio: {scrolledRatio}</li>
        </ul>
      </div>
  );
};

useActiveSection() hook accepts a callback function that is called when the active section changes.

Note that the state changes in the callback function will trigger re-renders which add performance overheads to your animations. You can replace the states with motion values from animation libraries like react-spring (opens in a new tab) or frame-motion (opens in a new tab) to avoid triggering re-renders.

Example

    Active Section = :
  • You are viewing section
  • Reading ratio: 0
RED
ORANGE
YELLOW
GREEN
BLUE
PURPLE

Note

To show the sticky background effect with a series of multiple tracked sections on its top, you can use StickyContainer to help you create the effect easily:

import { StickyContainer } from '@react-scrollytelling/layout';
 
 <StickyContainer
      overlay={
        <>
          {/* Put foreground sections here */}
          <TrackedSection
            sectionID="RED"
            className="border-rose-400 dark:border-rose-700 bg-rose-200 dark:bg-rose-800 rounded-t-lg pt-[50vh]"
          />
          {/* ... More tracked sections */}
        </>
      }
    >
        {/* Put sticky background here */}
        <StickyBackground />
</StickyContainer>

Alternatively, if you want to use the Tailwind CSS utility classes to style the sticky container, you can use StickyContainerTailwind instead of StickyContainer:

import { StickyContainerTailwind } from '@react-scrollytelling/layout';
 
<StickyContainerTailwind>
    {/* ...*/}
<StickyBackground />

In your Tailwind CSS configuration, remember to import @react-scrollytelling/layout so the classes can be applied:

module.exports = {
  // ...
  content: [
    // path to the library
    './node_modules/@react-scrollytelling/layout/**/*.{js,jsx,ts,tsx}',
  ],
};