Skip to content

Infinite Scroller

<quiet-infinite-scroller> stable since 1.0

Infinite scrollers provide an accessible container for continuously loading content feeds.

Infinite scrollers load new content automatically as users scroll down a feed. Instead of clicking "Next" buttons, content continuously appears as they approach the bottom. Infinite scroller follows the ARIA APG Infinite Scrolling Feed pattern for accessibility.

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12
Item 13
Item 14
Item 15
Item 16
Item 17
Item 18
Item 19
Item 20
<quiet-infinite-scroller id="infinite__overview">
  <div class="item">Item 1</div>
  <div class="item">Item 2</div>
  <div class="item">Item 3</div>
  <div class="item">Item 4</div>
  <div class="item">Item 5</div>
  <div class="item">Item 6</div>
  <div class="item">Item 7</div>
  <div class="item">Item 8</div>
  <div class="item">Item 9</div>
  <div class="item">Item 10</div>
  <div class="item">Item 11</div>
  <div class="item">Item 12</div>
  <div class="item">Item 13</div>
  <div class="item">Item 14</div>
  <div class="item">Item 15</div>
  <div class="item">Item 16</div>
  <div class="item">Item 17</div>
  <div class="item">Item 18</div>
  <div class="item">Item 19</div>
  <div class="item">Item 20</div>
</quiet-infinite-scroller>

<script>
  const infiniteScroll = document.getElementById('infinite__overview');
  let count = infiniteScroll.querySelectorAll('.item').length;

  infiniteScroll.addEventListener('quiet-load-more', async event => {
    // Simulate fetching content from a server
    setTimeout(() => {
      for (let i = 0; i < 20; i++) {
        const item = document.createElement('div');
        item.classList.add('item');
        item.textContent = `Item ${++count}`;
        infiniteScroll.append(item);
      }

      // We'll pretend there's nothing more to load after 100
      if (count >= 100) {
        infiniteScroll.complete();
        return;
      }      
    }, 300);
  });
</script>

<style>
  #infinite__overview {
    .item {
      padding: 1rem 1.5rem;

      &:not(:last-child) {
        border-bottom: solid 1px var(--quiet-neutral-stroke-softer);
      }
    }
  }
</style>

Examples Jump to heading

Providing initial content Jump to heading

You can slot just about any content you want into an infinite scroller container. The component watches the scroll position and dispatches the quiet-load-more event when users get close to the bottom.

<quiet-infinite-scroller label="News Feed">
  <!-- Initial content -->
  <article class="feed-item">First item</article>
  <article class="feed-item">Second item</article>
  <article class="feed-item">Third item</article>
  ...
</quiet-infinite-scroller>

Loading more content Jump to heading

In your code, listen for the quiet-load-more event. This is your cue to asynchronously load more content, e.g. from the server, and append it to the container. If no more content is available, call the component's complete() method to disable further loading.

const infiniteScroll = document.querySelector('quiet-infinite-scroll');
let currentPage = 1;

infiniteScroll.addEventListener('quiet-load-more', async () => {
  try {
    // Fetch new data from your API
    const response = await fetch(`/api/posts?page=${currentPage}`);
    const posts = await response.json();
    
    // Append posts to the feed
    posts.forEach(post => {
      const item = document.createElement('article');
      item.className = 'feed-item';
      item.innerHTML = `<h3>${post.title}</h3><p>${post.excerpt}</p>`;
      infiniteScroll.appendChild(item);
    });
    
    currentPage++;
    
    // Stop loading when no more content is available
    if (posts.length === 0) {
      infiniteScroll.complete();
    }
  } catch (error) {
    console.error('Failed to load more items:', error);
  }
});

To reenable loading, append additional items to the container or perform any DOM action that results in a slotchange.

When the container is empty initially or if the items don't cause the container to scroll, the quiet-load-more event will be dispatched immediately to request more items. This behavior allows the entire feed to load, regardless of content or screen size.

API Jump to heading

Importing Jump to heading

The autoloader is the recommended way to import components but, if you prefer to do it manually, the following code snippets will be helpful.

CDN npm

To manually import <quiet-infinite-scroller> from the CDN, use the following code.

import 'https://cdn.jsdelivr.net/npm/@quietui/quiet-browser@1.0.0/dist/components/infinite-scroller/infinite-scroller.js';

To manually import <quiet-infinite-scroller> from npm, use the following code.

import '@quietui/quiet/dist/components/infinite-scroller/infinite-scroller.js';

Slots Jump to heading

Infinite Scroller supports the following slots. Learn more about using slots

Name Description
(default) The default slot for feed items. Each item should have role="article" and be focusable.

Properties Jump to heading

Infinite Scroller has the following properties that can be set with corresponding attributes. In many cases, the attribute's name is the same as the property's name. If an attribute is different, it will be displayed after the property. Learn more about attributes and properties

Property / Attribute Description Reflects Type Default
label An accessible label for the feed. string ''
threshold The scroll threshold at which to trigger loading more items. Accepts percentages (e.g., "20%") or pixels (e.g., "200px"). string '20%'

Methods Jump to heading

Infinite Scroller supports the following methods. You can obtain a reference to the element and call them like functions in JavaScript. Learn more about methods

Name Description Arguments
complete() Mark the feed as completed, preventing further load events. Changing content in the default slot will reset this and re-enable infinite scrolling.

Events Jump to heading

Infinite Scroller dispatches the following custom events. You can listen to them the same way was native events. Learn more about custom events

Name Description
quiet-load-more Emitted when scrolling reaches the threshold and more items should be loaded.

Custom States Jump to heading

Infinite Scroller has the following custom states. You can target them with CSS using the selectors shown below. Learn more about custom states

Name Description CSS selector
loading Applied when the infinite scroller is loading more content. :state(loading)
complete Applied when the infinite scroller has no more content to load. :state(complete)

Dependencies Jump to heading

Infinite Scroller automatically imports the following elements. Sub-dependencies are also included in this list.

Search this website Toggle dark mode Get the code on GitHub Follow @quietui.org on Bluesky Follow @quiet_ui on X

    No results found