Skip to content

[cssom-view] Consider making scroll methods return promises #1562

Open
@markcellus

Description

@markcellus

Smooth scrolling has been introduced into the spec where the scroll happens over a period of time, which is great. However, I think it would be even more useful if scroll method returned a promise so the developer could wait until the scroll finishes before moving on to next set of tasks for things like triggering analytics data after scrolling, unloading resources when they've been scrolled out of view, parallax scrolling, etc.

Obviously scroll()ing an element that has scroll-behavior option set to auto makes scroll instant and is therefore not inherently asynchronous. But I think, to keep the API consistent, the scroll method should return a promise every time it is used.

So if you had the following HTML...

<div id="scroll-container" style="scroll-behavior: smooth;">
   <!-- other content here --> 
</div>

you can do this...

let element = document.getElementById('scroll-container');
element.scroll(0, 400).then(() => {
   // ...scroll has finished
});

Activity

markcellus

markcellus commented on Jun 25, 2017

@markcellus
Author

FWIW, here is a link to the relevant discussion where others have also +1'd this feature.

dartess

dartess commented on Apr 25, 2018

@dartess

in 2018 it is still very much needed, only now we will use it this way:

let element = document.getElementById('scroll-container');
await element.scroll(0, 400);
// ...scroll has finished

use case: set focus after scroll

tabatkins

tabatkins commented on Apr 25, 2018

@tabatkins
Member

Since all of the scrolling methods currently return void, they're very compatible with being upgraded into returning promises. I think this would be a fine feature, we just need implementor interest. I'll Agenda+ it to gauge support.

css-meeting-bot

css-meeting-bot commented on May 16, 2018

@css-meeting-bot
Member

The Working Group just discussed Consider making scroll methods return promises, and agreed to the following:

  • RESOLVED: add returning a promise to all scroll functions
The full IRC log of that discussion <dael> Topic: Consider making scroll methods return promises
<dael> github: https://github.com//issues/1562
<dael> TabAtkins: Right now all scrolling methods are void, return undefined. When they were instant that wwas fine. Now that there's smoothe scrolling it may be worthwhile to have something tell you when it's finished. Someone suggested that scroll methods return promises.
<dael> TabAtkins: I don't think they would ever fail.
<dael> TabAtkins: Upgrading void methods into promise returning is a standard way to do this and should be compat. As long as there's no impl I'd like to add.
<dael> Rossen_: Defined behavior for overlapping scroll timelines?
<dael> TabAtkins: Don't know, use case?
<dael> Rossen_: You want to impl your own overscroll behavior for a spring effect. When your scroll is complete you want to scroll down and back. I can see someone doing that. So I start a scroll for something fairly long in time and then I'll wait for the promise to do the little overscroll. But another scroll in the opposite dir happens.
<dael> TabAtkins: If a scroll is started and interrupted it's done and you fulfill promise.
<dael> Rossen_: So inturupt or complete fulfils.
<dael> TabAtkins: We only reject promises on errors and there's no sense the scroll throws an error
<dael> dbaron: You might want data on if inturpt.
<dael> TabAtkins: Agree. Should fulfill, but argument should give data
<dael> majidvp: Can you not read scroll offset with actual offset and it means inturrupt?
<dael> TabAtkins: No because you're interrupted mid-way. Using that as a method an interrupted will be forever pending unless you hit it by luck.
<dael> dbaron: I think it's an alternative to data, not tot he promise.
<dael> dbaron: That said, I think there are a bunch of scrolling operations where you don't know destination offset. YOu can cause scroll by page and you don't know pixel.
<dael> TabAtkins: And scroll into view is at least difficutl to cal
<dael> Rossen_: I would want to have something cleaner and richer for hints. When you intersect this with scroll snapping and you stop for a different reason...if you scroll by and need to scroll up more because a scroll snap has a mandatory scroll you'll overscroll based on target.
<dael> Rossen_: Meta point, I don't think anyone objects use case of promise pattern. I think the addition to this is adding some data that describes how this was fulfilled.
<dael> TabAtkins: I can see fulfill with an object that's an enum of completed or interrupted or something like that.
<dael> AmeliaBR: I suggest looking at web animations spec. Smoothe scroll is a type of animation and web animation uses lots of promises and chaining things like web animation after a complete smooth scroll. Compat here is useful.
<dael> TabAtkins: Agree. I didn't know about that but I will take a look at it.
<dael> majidvp: Another case is a scroll-into-view where we scroll multi scrollers and we need details on when we fulfill. I imagine after all scrolls are complete.
<dael> TabAtkins: Yes, if you have 2 nested scrollers inner is a bit and outer is a lot so inner completes fast. Makes sense. Good detail.
<dael> Rossen_: Is there a reason we wouldn't want this as an event that you can subscribe instead of adding promises to all scroll functions?
<AmeliaBR> s/promises and chaining/promises and I could see a use case for chaining/
<dbaron> https://developer.mozilla.org/en-US/docs/Web/Events/scroll
<dael> TabAtkins: Possibly. But if you only care about a given scroll you have to subscribe and then unsubscribe. Also there may be another scroll and you might get the wrong one. Event is useful, but doesn't do the use case of I want to know when this scroll is complete.
<dael> Rossen_: Okay. Makes sense.
<dael> Rossen_: Sounds like a feature that merits addition of promise. Likely details to work out.
<dael> Rossen_: Additional comments or objections to add returning a promise from all scroll functions?
<dael> RESOLVED: add returning a promise to all scroll functions
Nantris

Nantris commented on Nov 24, 2019

@Nantris

Is there an ETA for this being spec?

2 remaining items

webdevelopers-eu

webdevelopers-eu commented on Aug 19, 2024

@webdevelopers-eu

Unlike TabAtkins' opinion in the IRC chat, I strongly support the idea of implementing Promise rejection if a scroll is interrupted.

As I mentioned in #3744 , the intended effect of scrollIntoView is to bring the specified element into view. If this does not happen for any reason, the promise should be rejected, as the action was not fulfilled. There are specific scenarios where this should occur, such as:

  • The element is removed or stops being rendered before it reaches the visible part of the viewport.
  • The smooth, time-dependent scrolling is interrupted programmatically or by user action.

Simply put, the goal of scrollIntoView is to bring an element into view. If this is achieved, the promise should be fulfilled; if not, the promise should be rejected. This aligns with the natural and expected behavior that any programmer would anticipate when triggering an action intended to produce a specific result.

markcellus

markcellus commented on Oct 15, 2024

@markcellus
Author

If this is achieved, the promise should be fulfilled; if not, the promise should be rejected.

This is a valid point @webdevelopers-eu. But I think throwing an error may be unexpected for these cases and developers are probably likely to miss handling it. Is it possible to just abort/cancel the promise instead? That would make it so that an app handles this gracefully (by default) instead of abruptly throwing an error, which could potentially cause an entire website from working if the website is a SPA (or relies a lot on JS to operate).

webdevelopers-eu

webdevelopers-eu commented on Oct 16, 2024

@webdevelopers-eu

In that case, @markcellus, I can't see any other situation where a Promise rejection would occur, which essentially reduces the Promise to just being a callback. This undermines its purpose, as Promises are intended to handle success and failure cases, not just one. If we’re only using it to signal success and merely aborting in failure scenarios, we strip away the robustness of the Promise pattern and lose the benefit of built-in error handling.

tabatkins

tabatkins commented on Oct 16, 2024

@tabatkins
Member

In an async function, the promise is rejected only when the function throws an error. All other cases result in a fulfilled promise. This pattern is generally followed by other DOM functions that return promises; rejection is reserved for errors where we'd throw in a synchronous function.

In this case, we're just using the promise for its timing aspect.

flackr

flackr commented on Jun 23, 2025

@flackr
Contributor

In this case, we're just using the promise for its timing aspect.

Additionally, the promise can be passed an argument which includes the completion status of the scroll so that developers can choose to have different behavior depending on whether the scroll was completed or interrupted.

mustaqahmed

mustaqahmed commented on Jun 23, 2025

@mustaqahmed
Member

While implementing this, we found two Blink tests that are affected by a minor error handling change caused by this proposal here. I don't expect this corner case to be a compat problem, and wanted to check what other folks here think:

A JS parsing error caused by a malformed scroll*() call would no longer throw synchronously; instead it would return a Promise that would throw asynchronously. For example, in Blink the shouldThrow('window.scrollTo(x)') call here fails because the eval() is seeing a Promise object instead of an exception.

Anyone concerned?

tabatkins

tabatkins commented on Jun 23, 2025

@tabatkins
Member

I'm not too concerned, since that's a mistake in the first place and would be fixed by the author. Only places explicitly catching a thrown error and doing something meaningful with it would notice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Participants

      @frivoal@zcorpan@flackr@tabatkins@markcellus

      Issue actions

        [cssom-view] Consider making scroll methods return promises · Issue #1562 · w3c/csswg-drafts