DEV Community

loading...

Build infinite scroll in Svelte

Ersin Buckley
・2 min read

Svelte is an interesting framework because it is not really a framework. To be accurate, it is a compiler which turns your components into incredibly lean javascript that has no external dependencies on framework code. The component structure is appealing. You ship your CSS/HTML/Scripts in a single 'svelte' component file, where everything is bound and scoped locally.

The Problem

In my latest project, I want to display an infinite list of documents, each document could be up to a couple kb of markdown long, and there is an arbitrary number of documents. I want to focus on learning the framework, not a library or pre-made component, so I decided to implement the ability to quickly scroll this list on my own.

The underlying data-source is simple. Two API endpoints. But you could easily switch this out with your own API which involves a list too long to render all upfront.

When building a javascript heavy application, it's important to take advantage of what the platform affords us, and lazy loading an inifinite list is a very common technique used all across the web.

The Design

Endpoints:

  • /list list all the available keys.
  • /r/:key get back the document for the underlying key.

The Psuedo code

Get the list of keys
Take the first 10 items into an array
render the first 10 items
hook up an event that triggers when the user has scrolled to the end of the page
render the next 10 items
Enter fullscreen mode Exit fullscreen mode

The Implementation

<script>
// psuedo code -- but you get the idea right?!
const PAGE_LENGTH = 10
let docs = []
let loadingNextPage = false
let currentOffset = 0

start(0)

function start(offset) {
   getList() // BYO implementation of returning the list of data
     .then(keys => docs = keys.slice(0, offset + PAGE_LENGTH))
}
function scrollHandler() {
  // only allow the loading of new data if it is not already loading new data
  if (!loadingNextPage && (window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
    const previousScrollY = window.scrollY;
    loadingNextPage = true
    setTimeout(() => {
      window.scroll(0, previousScrollY)
      currentOffset += PAGE_LENGTH
      start(currentOffset)
      loadingNextPage = false
    })
  }
}
</script>
// hooks up the data to the loadingNextPage && (window.innerHeight + window.scrollY) >= document.body.offsetHeightnew 
<svelte:window on:scroll={scrollHandler} />
<div>
  {#each docs as doc}
    <Document name={doc}/>
  {/each}
</div>
Enter fullscreen mode Exit fullscreen mode

The key things we are depending on to make this all work are the <svelte:window on:scroll={scrollHandler}> and the framework keeping track of the local binding of the docs array.

The on scroll event is exactly the same as the scroll dom event.

The main gotcha with this is that you will generate many many scroll events and you only want to start loading new data when you reach near the end of the window. This is solved by the condition inside our scroll event handler loadingNextPage && (window.innerHeight + window.scrollY) >= document.body.offsetHeight

The Final note

Thanks for making it to the end of this tiny little tutorial. I am very open to feedback, on the format or content here.

Has this helped you understand Svelte, or the web?

Discussion (0)