v150 · Web APIs · Scrolling

Virtual Tour

A guided virtual tour uses await element.scrollTo() promises to visit each stop in sequence: scroll → wait for animation to complete → show arrival callout → pause → next stop. Without promises, the timing required fragile setTimeout guesses that broke on slow devices or when the user interrupted.

Tour viewport Stop — / 5
01
Introduction
The tour starts here. Programmatic scroll promises let you sequence smooth scrolls reliably — no setTimeout hacks.
Waiting
02
The API
element.scrollTo({ top, behavior: 'smooth' }) now returns a Promise that resolves when the scroll animation is complete.
Waiting
03
Chaining
Each stop is awaited before the next begins: await scrollTo(stop1); pause(1s); await scrollTo(stop2); — no race conditions.
Waiting
04
Parallel Scrolls
Promise.all([scrollA, scrollB]) lets you scroll two panes simultaneously and wait for both before proceeding to the next step.
Waiting
05
End of Tour
You have reached the last stop. The promise chain completed — every scroll finished before the next started.
Waiting
// Press "Start tour" to begin the scrolling sequence…
The tour uses await viewport.scrollTo({ top, behavior:'smooth' }) at each stop, then pauses 900ms before moving on. Every step is guaranteed to complete before the next begins.

source

let runToken = 0;

function smoothScrollTo(top) {
  const nativePromise = viewport.scrollTo({ top, behavior: "smooth" });
  if (nativePromise && typeof nativePromise.then === "function") {
    return nativePromise; // Chrome 150+: settles with the scroll.
  }

  // Earlier browsers return undefined. Resolve on scrollend instead of
  // immediately issuing the next scroll and skipping intermediate stops.
  return new Promise(resolve => {
    viewport.addEventListener("scrollend", resolve, { once: true });
  });
}

async function startTour() {
  const thisRun = ++runToken;
  for (let i = 0; i < 5; i++) {
    const stop = document.getElementById(`stop-${i}`);
    await smoothScrollTo(stop.offsetTop);
    if (thisRun !== runToken) return; // stopped or reset
    markVisited(i);
    if (i < 4) await sleep(900);
  }
}

function stopTour() {
  runToken++; // prevents the pending sequence from marking later stops
  viewport.scrollTo({ top: viewport.scrollTop, behavior: "instant" });
}

see also

implementation reference

Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗