Infinite Content Scrolling

Written by @phuang 28 December 2022

Infinite content scrolling is a design pattern that continuously loads content as the user scrolls towards the end of the page. It avoids pagination and increases user engagement. In this example, we have an infinite amount of quotations that loads as you continuously scroll to the end.

Code Snippet:

                                                
                                                <!-- this script is provided by www.javascriptfreecode.com coded by: Kerixa Inc. -->
<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Infinite Content Scrolling</title>

<!-- font awesome library include 4.7 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" integrity="sha512-5A8nwdMOWrSz20fDsjczgUidUBR8liPYU+WymTZP1lmY9G6Oc7HlZv156XqnsgNUzTyMefFTcsFH/tnJE/+xBg==" crossorigin="anonymous" referrerpolicy="no-referrer" />

<!-- font library -->
<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">

<!-- css styles -->
<style>
 
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap'); 

/* default light theme */
:root, html{
  margin: 0;
  padding: 0;
  font-family: "Inter", arial, monospace;

  --primary-color: #f45b69;
  --secondary-color:#456990;
  --background-color: white;
  --button-color: black;
  --button-bg-color: yellow;
  --opacity: 0.75;
}

/* dark-mode theme */
:root[data-theme="dark-mode"]{
  

}


/* main styles */
html, body{
  height: 200%;
  /* background-color: var(--background-color); */
  margin: 0;
  padding: 0;

}

body{
  position: relative;
  display: flex;
  justify-content: center;
  align-items: start;
}

*{
  box-sizing: border-box;
  font-family: "Inter", arial, monospace;
  font-size: 1rem;
  transition: all 0.5s ease-in-out;
}

a{
  text-decoration: none;
  font-weight: 600;
  color: var(--secondary-color);
}

a:hover{
  color: var(--primary-color); 
}


main{
  display: flex;
  justify-content: center;
  flex-direction: column;
  width: 100%;
}

section:first-child{
  margin: 0 auto;
}

section:last-child{
  display: flex;
  justify-content: center;
  width: 100%;
}
button{
  margin: 1rem auto;
}
ul{
  padding: 0;
}

.cards{
  margin: 2rem;
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  width: 100%;
}

.cards .card-item{

  width: 47.5%;

  box-shadow: 0 2px 4px rgb(0 0 0 / 0.1);
  border-radius: 0.25rem;

  border: 1px solid lightgrey;
  display:flex;

  margin: 1.25%;
}

.cards .card-item .card-content{
  display: flex;
  flex-direction: column;
  padding: 1rem;

  justify-content: space-between;
}

.cards .card-item .card-content p:last-child{
  font-weight: bold;
}

.d-none{
  display: none;
}

/* skeleton animation */

.skeleton{
  width: 47.5%;
  margin: 1.25%;
  
  box-shadow: 0 2px 4px rgb(0 0 0 / 0.1);
  border-radius: 0.25rem;

  border: 1px solid lightgrey;
  display:flex;
}

.skeleton .card-content{
  width: 100%;
  justify-content: flex-start !important;
  padding: 1rem;
}

.skeleton .card-content p{
  height: 1.25rem;
  border-radius: 0.125rem;
  background-color: rgb(240, 240, 240);
  margin: 0.5rem ;
  padding: 0 1rem;

  width: 100%;
  animation: skeleton_animation 1s ease-in-out infinite;
}

.skeleton .card-content p:nth-child(2){
  width: 40%;
}

.skeleton .card-content p:last-child{
  margin-top: 2rem;
  width: 60%;
}


@keyframes skeleton_animation {
  0%{
    background-color: rgb(240, 240, 240);
  }
  50%{
    background-color: rgb(225, 225, 225);
  }
  100%{
    background-color: rgb(240, 240, 240);
  }
}

</style>
</head>

<body>


<main>

  <section>
    <button class="js-reset">Reset</button>
  </section>

  <section>
    <ul class="cards">
    </ul>
  </section>



</main>

<script>


/*   

Tutorial Description

Infinite content scrolling is a design pattern that continuously loads content as the user scrolls 
towards the end of the page. It avoids pagination and increases user engagement. In this example, we have 
an infinite amount of quotations that loads as you continuously scroll to the end.

*/
let page = 1;
const MAXIMUM_QUOTE_LMT = 10;
const button = document.querySelector(".js-reset");
let url = "https://api.javascripttutorial.net/v1/quotes/?limit=" + MAXIMUM_QUOTE_LMT + "&page=" + page;


function updateUrl(page){
  url = "https://api.javascripttutorial.net/v1/quotes/?limit=" + MAXIMUM_QUOTE_LMT + "&page=" + page;
}

if(button != null){
  button.addEventListener("click", event => {
  
    updateUrl(1);
    
    document.querySelector(".cards").innerHTML = "";

    loadQuotes(url).then(data => {
      populateQuotesToCards(data);
    })
  })
}

// set up intersection observer 
const options = {
  root: null,
  rootMargin: "0px",
  threshold: 1.0
}

let callback = (entries, observer) => {

  entries.forEach( (entry) => {
    
    if(entry.intersectionRatio >= 1){

      // update page
      updateUrl(page++);

      console.log(url)
      loadQuotes(url).then(data => {
        populateQuotesToCards(data);
      })

      observer.unobserve(entry.target);

    }
  })
}

let observer = new IntersectionObserver(callback, options);

function getQuote(url){

  loadSkeletonAnimation();

    return new Promise((resolve, reject) => {

      fetch(url, {method: "get"}).then(response => {

        if(response.ok){

          response.json().then(res => {
            removeSkeletonAnimation(res.data.length);
            resolve(res.data);
          })
        }else{

          removeSkeletonAnimation();
          reject("Error encountered fetching posts");
        }
      })
    })
}

async function loadQuotes(url){
  return await getQuote(url);
}


// Loads a skeleton animations for each pending cards
function loadSkeletonAnimation(){

  const container = document.querySelector(".cards");

  if(container != null){

    for(let i = 0; i < MAXIMUM_QUOTE_LMT; i++){

      const card_item = document.createElement("li");
      card_item.classList.add("card-item", "skeleton", "pending");

      const content = document.createElement("div");
      content.classList.add("card-content");

      for(let i = 0; i < 3; i++){
        
        const p = document.createElement("p");
        content.appendChild(p);
      }

      card_item.appendChild(content);
      container.appendChild(card_item);

    }
  }
}


// Remove skeleton animations on the cards 
function removeSkeletonAnimation(dataAmt = 0){

  const cards = document.querySelectorAll(".skeleton");
  const amt = cards.length - dataAmt;
  const cards_container = document.querySelector(".cards");

  for(let i = 0; i < amt; i++){
    cards_container.lastChild.remove();  
  }
 
  if(cards != null){

    cards.forEach(card => {
      card.classList.remove("skeleton");

      let content = card.querySelector(".card-content");
      content.innerHTML = "";

      for(let i = 0; i < 2; i++){
        content.appendChild(document.createElement("p"));
      }
    })
  }
}

function populateQuotesToCards(data){

  const cards = document.querySelectorAll(".pending");

  observer.observe(cards[cards.length - 1]);

  if(cards != null){

    for(let i = 0; i < cards.length; i++){

      const content_containers = cards[i].querySelectorAll("p");

      content_containers[0].textContent = "\"" + data[i].quote + "\"";
      content_containers[1].textContent = data[i].author;

      cards[i].classList.remove("pending");
    }  
  }
}

loadQuotes(url).then(data => {
  populateQuotesToCards(data);
})

</script>
</body>
</html><a target='_blank' href='www.javascriptfreecode.com' style='font-size: 8pt; text-decoration: none'>JavaScript Best Codes</a>                                                
                                            

Example:


About @phuang

Help desk analyst transitioning to a full-stack developer role. Hoping to learn and collaborate with everyone. Happy coding!

P

Comments


Here you can leave us commments. Let us know what you think about this code tutorial!

0 / 300

TRENDING POST
1
2
3
4
5
VISITORS
Online Users: 12
Recent Members: Estevan Belo, Shahmeer, coolcoco7, SmitaPatil25, owoboycute
advertisement 2