How to restore scroll position in live view app?

What’s the recommended way to restore scroll position in live view apps?

Right now in the default installation, when navigating forward and then back, the scroll position is lost.

Are there any plans to handle it by default?

scroll position should be maintained when clicking back and forward, the same way browser’s handle it because we use push state and let the browser handle the scroll. The only time we scroll to the top of the back is when you click a live_redirect link, which is the same behavior of following a real anchor. Are you seeing differently? What steps and which browser?

3 Likes

Clicking a live_redirect and then going back scrolls to the top in Chrome Version 81.0.4044.138 (Official Build) (64-bit) and Safari Version 13.1 (15609.1.20.111.8). I’ll try and create a repo on github.

Hm, I’m a bit confused, so clicking a live_redirect link and going back isn’t supposed to restore the previous scroll position?

Repro: https://github.com/syfgkjasdkn/scroll-position-live-view

Going back on link restores the position, but going back on live_redirect doesn’t.

Recording: https://www.dropbox.com/s/hkl11k3l1b8favc/scroll-demo.mp4?dl=0

yeah use live_patch…

now you might find yourself with the issue of the page not scrolling to top when navigation… eg scroll to bottom on first page and then navigate(live_patch) and find yourself on middle/bottom of new page (I did)
my app has in live.html.leex:
top_nav_component
wrapper_component
footer_component

where the wrapper then acts as kind of a router and renders the different pages…

first I just did a hook on the uri_path with a scroll to top - that worked when clicking links (live_patch) - but going back it be at the top - and forward at the top…

so I ended up putting a hook on all my live_patch links, that sets window.ready_to_scroll = true;:

<%= live_patch to: "#{@locale_prepend}/about", as: :about, replace: false, phx_hook: "ScrollToTop", class: "block sm:mr-4 sm:w-1/4" do %>
  link span/svg
    <% end %>
Hooks.ScrollToTop = {
  mounted() {
    this.el.addEventListener("click", e => {
      if (window.location.href == this.el.href) {
       window.scroll({
        top: 0, 
        left: 0, 
        behavior: 'smooth'
        });
      } else{
        window.ready_to_scroll = true;
      }

    })
  }
}

nb: that if it doesn’t navigate (eg I’m on /products and click on /products in the footer or top nav - I assume the user wants scroll to top)

then the uri_path hook (or in my case “active_page” since I don’t navigate on locale change - which changes the uri_path)

<span class="hidden" id="active_page" phx-hook="ChangeActivePage"><%= assigns[:active_page] %><%= assigns[:navigate_counter] %></span>

and the hook, notice the setTimeout… honestly can’t remember if it’s important :man_facepalming: :

Hooks. ChangeActivePage = {
  updated() {
    if (window.ready_to_scroll == true) {
      window.ready_to_scroll = false;
    
      setTimeout(function(){ 
       window.scroll({
          top: 0, 
          left: 0, 
          //behavior: 'smooth'
        });
       }, 30);
    }

  }
}

that way clicking links with live_patch scrolls to top - but going back/forward in browser doesn’t…

shoot me a DM and I can send you the link to the prod site for you to check out…

1 Like

I don’t think I can use live_patch since I’m redirecting to a different live view. I hope there is a simpler solution …

I’ve opened an issue on github: https://github.com/phoenixframework/phoenix_live_view/issues/897