Infinite scroll lets content load continuously as users move down the page, unlike the click-to-load method of traditional pagination. This feature can offer a smoother experience, especially on mobile devices.

Discover how to set up infinite scroll using plain HTML, CSS, and JavaScript.

Setting Up the Frontend

Start with a basic HTML structure to display your content. Here's an example:

 <!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="style.css" />
</head>
<body>
    <h1>Infinite Scroll Page</h1>

    <div class="products__list">
      <img src="https://fakestoreapi.com/img/71li-ujtlUL._AC_UX679_.jpg"
           alt="Jacket" />

      <img src="https://fakestoreapi.com/img/71li-ujtlUL._AC_UX679_.jpg"
           alt="Jacket" />

      <img src="https://fakestoreapi.com/img/71li-ujtlUL._AC_UX679_.jpg"
           alt="Jacket" />

      <img src="https://fakestoreapi.com/img/71li-ujtlUL._AC_UX679_.jpg"
           alt="Jacket" />

      <img src="https://fakestoreapi.com/img/71li-ujtlUL._AC_UX679_.jpg"
           alt="Jacket" />

      <img src="https://fakestoreapi.com/img/71li-ujtlUL._AC_UX679_.jpg"
           alt="Jacket" />
    </div>

    <script src="script.js"></script>
</body>
</html>

This page contains a series of placeholder images and references two resources: a CSS file and a JavaScript file.

CSS Styling for Scrollable Content

To display the placeholder images in a grid, add the following CSS to your style.css file:

 * {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html { font-size: 62.5%; }

body {
  font-family: Cambria, Times, "Times New Roman", serif;
}

h1 {
  text-align: center;
  font-size: 5rem;
  padding: 2rem;
}

img {
  width: 100%;
  display: block;
}

.products__list {
  display: flex;
  flex-wrap: wrap;
  gap: 2rem;
  justify-content: center;
}

.products__list > * {
  width: calc(33% - 2rem);
}

.loading-indicator {
  display: none;
  position: absolute;
  bottom: 30px;
  left: 50%;
  background: #333;
  padding: 1rem 2rem;
  color: #fff;
  border-radius: 10px;
  transform: translateX(-50%);
}

At the moment, your page should look like this:

initial page after html and css added
Made by David Jaja -- No attribution Required

Core Implementation With JS

Edit script.js. To implement infinite scroll, you need to detect when the user has scrolled near the bottom of the content container or page.

 "use strict";

window.addEventListener("scroll", () => {
  if (
    window.scrollY + window.innerHeight >=
      document.documentElement.scrollHeight - 100
  ) {
    // User is near the bottom, fetch more content
    fetchMoreContent();
  }
});

Then, create a function to fetch more placeholder data.

 async function fetchMoreContent() {
  try {
    let response = await fetch("https://fakestoreapi.com/products?limit=3");

    if (!response.ok) {
      throw new Error("Network response was not ok");
    }

    let data = await response.json();
    console.log(data);
  } catch (error) {
    console.error("There was a problem fetching new content:", error);
  } finally {
    console.log("Fetch function fired");
  }
}

For this project, you can use the API from fakestoreapi.

To confirm your data is being fetched on scroll, take a look at the console:

Confirming the fetch function was called on scroll
Made by David Jaja -- No attribution required

You’ll notice your data is being fetched multiple times on scroll which can be a factor that hurts device performance. To prevent this, create an initial fetching state of the data:

 let isFetching = false;

Then, modify your fetch function to only fetch data after a previous fetch has finished.

 async function fetchMoreContent() {
  if (isFetching) return; // Exit if already fetching

  isFetching = true; // Set the flag to true

  try {
    let response = await fetch("https://fakestoreapi.com/products?limit=3");

    if (!response.ok) {
      throw new Error("Network response was not ok");
    }

    let data = await response.json();
  } catch (error) {
    console.error("There was a problem fetching new content:", error);
  } finally {
    console.log("Fetch function fired");
    isFetching = false; // Reset the flag to false
  }
}

Displaying the New Content

To display new content when the user scrolls down the page, create a function that appends the images to the parent container.

First, select the parent element:

 const productsList = document.querySelector(".products__list");

Then, create a function to append content.

 function displayNewContent(data) {
  data.forEach((item) => {
    const imgElement = document.createElement("img");
    imgElement.src = item.image;
    imgElement.alt = item.title;
    productsList.appendChild(imgElement); // Append to productsList container
  });
}

Finally, modify your fetch function and pass the fetched data to the append function.

 async function fetchMoreContent() {
  if (isFetching) return;

  isFetching = true;

  try {
    let response = await fetch("https://fakestoreapi.com/products?limit=3");

    if (!response.ok) {
      throw new Error("Network response was not ok");
    }

    let data = await response.json();
    displayNewContent(data);
  } catch (error) {
    console.error("There was a problem fetching new content:", error);
  } finally {
    console.log("Fetch function fired");
    isFetching = false;
  }
}

And with that, your infinite scroll now works.

Infinite scroll working
Made by David Jaja -- No attribution required

Infinite Scroll Enhancements

To enhance user experience, you can display a loading indicator when fetching new content. Start by adding this HTML.

 <h1 class="loading-indicator">Loading...</h1>

Then select the loading element.

 const loadingIndicator = document.querySelector(".loading-indicator");

Finally, create two functions to toggle the visibility of the loading indicator.

 function showLoadingIndicator() {
  loadingIndicator.style.display = "block";
  console.log("Loading...");
}

function hideLoadingIndicator() {
  loadingIndicator.style.display = "none";
  console.log("Finished loading.");
}

Then, add them to the fetch function.

 async function fetchMoreContent() {
  if (isFetching) return; // Exit if already fetching

  isFetching = true;
  showLoadingIndicator(); // Show loader

  try {
    let response = await fetch("https://fakestoreapi.com/products?limit=3");

    if (!response.ok) {
      throw new Error("Network response was not ok");
    }

    let data = await response.json();
    displayNewContent(data);
  } catch (error) {
    console.error("There was a problem fetching new content:", error);
  } finally {
    console.log("Fetch function fired");
    hideLoadingIndicator(); // Hide loader
    isFetching = false;
 }
}

Which gives:

Good Practices for Infinite Scroll

Some best practices to follow include:

  • Don't fetch too many items simultaneously. This can overwhelm the browser and degrade performance.
  • Instead of fetching content immediately upon detecting a scroll event, use a debounce function to delay the fetch slightly. This can prevent excessive network requests.
  • Not all users prefer infinite scrolling. Offer an option to use a pagination component if desired.
  • If there's no more content to load, inform the user instead of continuously trying to fetch more content.

Mastering Seamless Content Loading

Infinite scrolling lets users browse content smoothly, and it's great for people using mobile devices. If you use the tips and important advice from this article, you can add this feature to your websites.

Remember to think about how the users feel when they use your site. Show things like progress signs and error notes to make sure the user knows what's happening.