Infinite Scroll
Planted:
Status: seed

An infinite scrolling page continually fetches more content as the user scrolls. Commonly used when the page's content is too big to handle in 1 request. For example, Pinterest's landing page. It displays a list of items that are paginated (grouped in batches of 40 for example). On page load, the 1st batch is displayed. As the user scrolls, but before they reach the bottom, a request is made to fetch the next batch. This continues until there are no more batches. This approach to loading content removes the need for a user action to see the next batch. For example, clicking the Next link at the bottom of a Google search.
1st Batch
To create an infinite scroll, we will pretend we have an endpoint that batches items in groups of 10.
Items will be rendered on the page in a vertical list.
The 1st batch will be hardcoded in HTML representing a server-side render.
In case the user scrolls fast enough to reach the bottom of the list before the next batch of results has been fetched,
an additional list item will be added with the text Loading...
.
localhost:3000
<ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> <li>8</li> <li>9</li> <li>10</li> <li id="loader">Loading...</li> </ul>
Next Batch
To fetch more items, create an element we'll refer to as fetchTrigger within the <ul />
.
Set:
- ▪
<ul />
toposition: relative
- ▪ fetchTrigger to
position: absolute
,bottom: 0
. Making it anchored to the bottom of the list.
Observe fetchTrigger using the Intersection Observer, set the following in the options object:
- ▪ omit the
root
property - ▪
threshold: 0
This sets the viewport as the root.
When 1px
of fetchTrigger
intersects it, a callback will be executed.
Create a function that fetches the next batch and adds it to the list.
Call it when the observer is triggered and isIntersecting: true
.
localhost:3000
const fetchTrigger = document.querySelector("#fetchTrigger"); const ul = document.querySelector("ul"); const loader = document.querySelector("#loader"); const options = { rootMargin: "0px", threshold: 0, } let lastFetchedPage = 0; let isFetching = false; async function onIntersect() { isFetching = true; lastFetchedPage++; const data = await fetchData(lastFetchedPage); const lis = createLis(data); ul.insertBefore(lis, loader); isFetching = false; } function callback(entries, observer) { const { isIntersecting } = entries[0]; if (isIntersecting && !isFetching) { onIntersect(); } } const observer = new IntersectionObserver(callback, options); observer.observe(fetchTrigger);
The height of fetchTrigger will determine how far the user has to be from the bottom of the page to trigger a fetch.
Because it should not be seen or interacted with, set pointer-events: none
and aria-hidden="true"
.
In the example above, it has a background color for demo purposes only.
Where to Next?


