router
router copied to clipboard
Restore scroll position on navigation
As Flow I want Vaadin.Router to support restoring scroll position on navigation in the same way it works in Flow 1.0 so that the future versions of Vaadin Flow could switch to Vaadin.Router instead of the own implementation.
NOTE: react-router does not have any explicit support for scroll position restoration. Their position is that browsers do that by default quite well already: https://reacttraining.com/react-router/web/guides/scroll-restoration
A reference to the pwa-helpers router: https://github.com/Polymer/pwa-helpers/pull/14
Any option similar to https://github.com/Polymer/pwa-helpers/pull/14?
Because the event.type
is always vaadin-router-location-changed
.
do we have some kind of advance for this issue?
Related example: https://stackblitz.com/edit/lit-element-demo-zejjsv
Steps:
- Go to home and scroll to bottom
- Click on
Sam's profile
Now the scroll go to the top - Scroll to the bottom and click on
Home
The scroll remains
It seems that the problem is the lazy load of the view using dynamic import()
.
Now If you uncomment the static imports, it always keeps the scroll:
import './views/home-view.js';
import './views/profile-view.js';
import './views/not-found-view.js';
There are any workaround with this? Thanks in advance!
One way to reset scroll position would be to add a listener for the vaadin-router-location-changed
event:
window.addEventListener('vaadin-router-location-changed', e => {
window.scrollTo(0, 0);
});
A more elaborate solution would require changes in the Router APIs. I can think of two different use cases. Does any of that look relevant to your app?
- if you want to reset scroll position when navigation is triggered by clicking a link, but not when it's triggered by the browser 'back' button
That would require passing some information from the navigation trigger along with the event so that it's possible to write the code like
window.addEventListener('vaadin-router-location-changed', e => { if (e.detail.trigger === 'click') { window.scrollTo(0, 0); } });
- if you want to save and restore the exact scroll position for each route
That would require keeping track of the history of scroll positions for each route and passing that along with the event so that it's possible to write the code like
window.addEventListener('vaadin-router-location-changed', e => { if (e.detail.savedScrollPosition) { window.scrollTo(e.detail.savedScrollPosition.x, e.detail.savedScrollPosition.y); } });
Thanks for the answer, @vlukashov!
I discard the first option because in many situations we shouldn't scroll to top.
As before I was using the Polymer/pwa-helpers
router, the second option seems really interesting! Easy and simple. But I don't have a strong opinion. Also the third looks nice.
Adding a link to the Vue router implementation for reference.
I think we should use the state
serializable object in the pushState
API, each time router calls to the method should pass the scroll position, then on popState
it can be restored.
Not sure about how to make it configurable by the user in order to configure which routes needs to store/restore scrolling but could be an extra property in the route entry
Note: as discussed today with https://vaadin.com team, we might try history.scrollPosition
:
https://caniuse.com/#feat=mdn-api_history_scrollrestoration
It supports all the target browsers of Vaadin 15 (don't be confused with Edge 80, the data seems to be incorrect). IMO this is something worth prototyping to see if it works for us.
Just opening up a discussion here: Should we consider the use case of scrolling to an anchor in the page instead of a scroll position?
Any news here?
Very interested too in this feature and in the scroll to anchor from @miladkdz
Hi, any updates on this issue?
Not sure if I have a special case, but for me scroll is restored properly on page changes, but when I go to a new page, it doesn't move the scroll position to the top. So I'm pretty confused.
At the very least, if we had something like e.detail.originalEvent
with the "vaadin-router-location-changed" event, then we could inspect it and do what we like.
For example, change src/triggers/popstate.js to:
function vaadinRouterGlobalPopstateHandler(originalEvent) {
if (originalEvent.state === 'vaadin-router-ignore') {
return;
}
const {pathname, search, hash} = window.location;
fireRouterEvent('go', {pathname, search, hash, originalEvent});
}
And then do something similar in vaadinRouterGlobalClickHandler()
as well, now we can see if the event came from a click or popstate, and go from there.
Ultimately, I think saving and restoring the scroll position should be a top priority. I've used the router in a few places, and this issue is mysteriously present or not, and I can't figure out why. When it is present, it is a debilitating user experience.
Hello, any updates?👀
It's not ideal, but we have a simple patch to deal with it here: https://github.com/IBM/pwa-lit-template/issues/1