demo · v149

Scroll Progress Tracker

Programmatic scrollTo() returns a Promise that resolves with { interrupted: false } on completion or { interrupted: true } if another scroll interrupts it. Chain each chapter scroll sequentially using await — the progress bar only advances when each scroll actually lands, not on a timer.

Click Start tour to scroll through all five chapters automatically. Interrupt at any time — the Promise resolves with { interrupted: true } and the progress bar pauses. Resume to continue from the interrupted chapter. Click any chapter in the chapter strip to jump directly.
Speed:
0 / 5 chapters
Current chapter
Completed0
Interruptions0
Status
Click "Start tour" to begin the promise-driven scroll sequence.
// Promise-chained chapter scroll with progress tracking
async function runTour(chapters, scroller) {
  for (let i = 0; i < chapters.length; i++) {
    const chapter = chapters[i];
    const targetY = chapter.offsetTop;

    updateProgress(i, 'scrolling');

    const result = await scroller.scrollTo({
      top: targetY,
      behavior: 'smooth',
    });

    if (result.interrupted) {
      // User scrolled away — pause here and wait for resume
      log('Chapter ' + (i+1) + ' interrupted — awaiting resume…');
      await waitForResume();       // user clicks Resume button
      i--;                         // retry the interrupted chapter
      continue;
    }

    updateProgress(i + 1, 'reached');
    log('Chapter ' + (i+1) + ' ✓ — promise resolved { interrupted: false }');
  }
}

// Without promises, you'd need setTimeout guesses or IntersectionObserver
// to know if a programmatic scroll "landed". The promise makes it precise.

see also