How can I load a long list and stay/start on the bottom of the view without scrolling

We have a message view in our app where we on initial rendering load a list of messages which are then rendered, going from <div>Loading ....</div> to [<Message>,<Message>,...,<InputBox>] (pseudo-jsx). Upon loading, the view is extended to many times the screen length, so we need to scroll to the bottom onLoad(). This is bothersome :

  • lazy loading images in the older parts of the conversation won’t work, as we "scroll past" them, triggering loading
  • there should be no need to do scrollTo(99999): we want to start a freshly loaded page on the bottom!

So how can I have the initial "scroll position" of a container be the bottom of the container? This seems like a quite basic thing.

5 thoughts on “How can I load a long list and stay/start on the bottom of the view without scrolling”

  1. The following contrived example is designed to show you one possible solution by emulating your scenario. If I have this wrong please correct me.

    (React example linked at bottom)

    Ten images are loaded into individual <div> elements. To emulate network/loading delay each <div><img></div> is loaded every 1/2 second. Notice that nothing is visible while this happens other than the "Loading…" placeholder. Five seconds later, after all are loaded, a custom event is fired to indicate the loading is complete. The very last image will be dark blue rather than the light blue of the others.

    An event handler responds to the custom event by removing the "Loading…" indicator, scrolling to the bottom <div> and finally setting visibility of the entire section to visible.

    Note the <div>s just appear and the <section> has been scrolled to the bottom. The bottom <div> is the dark blue one.

    const container = document.querySelector('section');
    const divsToAdd = 10
    let divCounter = 0;
    const interval = setInterval(addDiv, 500);
    
    document.addEventListener('panelLoadComplete', () => {
      document.querySelector('section span:first-child').remove();
      document.querySelector('section div:last-child').scrollIntoView();
      container.style.visibility = 'visible';
    });
    
    function addDiv() {
      const div = document.createElement('div');
      const img = document.createElement('img');
      div.style.display = 'inherit';
      div.appendChild(img);
      container.appendChild(div);
      if (divCounter === divsToAdd) { // is last - dark blue
        img.src = "https://via.placeholder.com/100/0000ff"
      } else {
        img.src = "https://via.placeholder.com/100/0088ff"
      }
      if (++divCounter > divsToAdd) {
        clearInterval(interval);
        document.dispatchEvent(new CustomEvent('panelLoadComplete'));
      }
    }
    section {
      visibility: hidden;
    }
    
    section span:first-child {
      visibility: visible;
    }
    
    section>div:first-child {
      background-color: lightblue;
      width: 100px;
      height: 100px;
    }
    
    section>div:last-child {
      background-color: darkblue;
      width: 100px;
      height: 100px;
    }
    <section>
      <span>Loading... (patience: this takes ~5 seconds)</span>
    </section>

    Finally, a simple React version without the interval timer:

    React Example StackBlitz

    Reply

Leave a Comment