v150 · Web APIs · Scrolling
Programmatic scroll promises
Chrome 150 makes element.scrollTo(), element.scrollBy(), and element.scrollIntoView() return Promise<void> when called with behavior: 'smooth'. The promise resolves when the scroll animation completes, enabling await-based scroll sequences and eliminating the need for scroll event listeners or arbitrary timeouts.
concepts
-
Scroll Promise Demo
Interactive buttons that
awaitscroll completion before reporting done. Compare with the old approach usingscrollevents. Shows how the promise correctly resolves after the smooth scroll animation ends. -
Scroll Sequence
Chains multiple smooth scrolls using
await— scroll to item 1, wait, then scroll to item 2, wait, then back. Without promises, this required fragilesetTimeoutguesses or complex scroll-end detection. -
Parallel Scroll Race
Two scrollable lanes, scrolled simultaneously.
Promise.all()waits until both finish before triggering a shared action — a pattern that previously required ad-hoc counter state or dual event listeners. -
Lazy Reveal
"Load more" appends new feed items hidden, scrolls to them, and only after the promise resolves fades them in. The reveal animation is sequenced on scroll completion — no
setTimeoutguess needed. -
Virtual Tour
A guided 5-stop virtual tour that uses
await viewport.scrollTo({ behavior: 'smooth' })to visit each stop in sequence — scroll, wait for animation to complete, show arrival callout, pause, advance. An event log timestamps each scroll start and arrival. Without promises, the pause timing was a fragilesetTimeoutguess. -
Interrupted scroll promise
When a smooth scroll is interrupted — by a second
scrollTo()or a user gesture — Chrome 150 resolves the promise at the new settled position, not rejects. Try both interruption sources and confirm theawaitchain continues without throwing, regardless of where the scroll stopped.
why it shipped
Smooth scrolling via scrollTo({ behavior: 'smooth' }) starts an asynchronous animation, but the call returned undefined — there was no way to know when it finished. Common workarounds were: using setTimeout with an estimated duration (fragile), or watching the scroll event with an idle timer (complex). Neither handled cases where the user interrupted the scroll. Chrome 150 returns a proper Promise that resolves when the scroll settles, including interrupted scrolls that settle at a new position.
the API
// Before Chrome 150: returns undefined
element.scrollTo({ top: 500, behavior: 'smooth' });
// Chrome 150+: returns Promise<void>
await element.scrollTo({ top: 500, behavior: 'smooth' });
console.log('Scroll complete');
// Chain scroll sequences
await element.scrollTo({ top: 0, behavior: 'smooth' });
await element.scrollTo({ top: 500, behavior: 'smooth' });
await element.scrollTo({ top: 250, behavior: 'smooth' });
// scrollIntoView also returns Promise
await heading.scrollIntoView({ behavior: 'smooth', block: 'start' });
console.log('Heading is now in view');
// Instant scroll still returns Promise (resolves immediately)
await element.scrollTo({ top: 0, behavior: 'instant' });
// If scroll is interrupted, promise resolves at new settled position
// (does not reject)
references
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗