Mismatch between scroll and focus handling
jakearchibald opened this issue · 5 comments
The default focus behaviour is to reset focus, which is appropriate behaviour if the page is changing significantly, but not in cases like tabbed navigation.
This behaviour was decided in #202 to match MPA behaviour.
However, it seems like current scroll behaviour is out of step with this intent. In a regular MPA, when you navigate via either push/replace, scrolling is reset to 0,0. It feels like this should happen here too.
I'm not sure if this should be rolled into the current scroll option, or whether it needs a separate scrollReset
option.
This came up in discussion with @annevk as well; it slipped out of my brain before I could file it. Thanks for finding this and bringing it up.
The desire for symmetry between scroll and focus is indeed what makes this hard. A quick fix would be to add a scrollReset
option which only applies to push/replace/reload (or maybe only push??). And maybe that's the right thing to do. But if we want to take a step back the picture gets more complicated...
The cross-document nav experience is:
- Scroll resets on push/replace
- Scroll restores on reload/traverse
- Focus resets on push/replace/reload/non-bfcache traverse
- Focus restores on bfcache traverse
The current navigation API default experience for same-document navs is:
- Scroll stays the same on push/replace/reload
- Scroll restores on traverse
- Focus resets on push/replace/reload/traverse
We've been treating focus restore as something that we can't do by default, because of the problem of identifying the "same" DOM element. That seems like a safe bet to me. But we could probably fix the scroll reset/restore behavior.
Proposal:
- A separate
scrollReset: "after-transition"
or"manual"
, default"after-transition"
. This applies to push/replace. - Update
scrollRestoration: "after-transition"
to apply to reload. This might be a bit difficult since same-document "reloads" are basically no-ops right now, but hopefully we can try to make it work.
These are both compat-impacting changes. They would bring us to
The proposed navigation API default experience for same-document navs is:
- Scroll resets on push/replace
- Scroll restores on reload/traverse
- Focus resets on push/replace/reload/traverse
which is close to the cross-document nav experience.
Scroll resets on push/replace
The case I'm unsure about is hash-change navigations.
I'm happy with scrollReset
as an option. The only reasons I thought about rolling them into one option is that scroll resetting is a little bit like a restoration, but it's restoring it to 0,0. You never get resetting and restoring happening on the same navigation.
The case I'm unsure about is hash-change navigations.
If you call transitionWhile()
on a hashchange navigation, you are opting out of the usual navigate-to-a-fragment anyway. (This is why a lot of the demo code has if (!e.hashChange)
.)
Whereas, if anyone was using the hash to store information that was not a target element (e.g., UI state like which tab was open) they might want resetting behavior...
So I think it would be OK.
You never get resetting and restoring happening on the same navigation.
That's a good point, and it would be nice to unify. However:
- I can't think of any good name that covers both resetting and restoration. Can you?
- You might want to control them individually. This is easy if they're separate, e.g.
{ scrollRestoration: "manual", scrollReset: "after-transition" }
. It's harder if they're combined; you need do to{ bikeshed: e.navigationType === "traverse" || e.navigationType === "reload" ? "manual" : "after-transition" }
.
These are not very strong objections, so if we can think of a good name it still might be better to combine.
I can't think of a good name either. Given the above, it seems fine for them to be seperate options.