Skip to main content

Load More v1.0.0

Allow user to reveal additional content by pressing a button to load more items dynamically.

Default Setup Anchor (Default Setup)

Experimental: Experimental examples or components may require additional work, further testing, and may not be fully supported or accessible. They should be carefully evaluated before being used in a production environment.

<div class="load-more">

    <div class="load-more__msg" aria-live="polite"></div>
  
    <ul class="load-more__container" role="list">
  
      <li class="load-more__item">
  
        <a href="#!">
  
          <img src="https://radancy.dev/placeholder.png" alt="">
  
          <span>Item 1</span>
  
        </a>
  
      </li>
  
      <li class="load-more__item">
  
        <a href="#!">
  
          <img src="https://radancy.dev/placeholder.png" alt="">
  
          <span>Item 2</span>
  
        </a>
  
      </li>
  
      <li class="load-more__item">
  
        <a href="#!">
  
          <img src="https://radancy.dev/placeholder.png" alt="">
  
          <span>Item 3</span>
  
        </a>
  
      </li>
  
      <li class="load-more__item">
  
        <a href="#!">
  
          <img src="https://radancy.dev/placeholder.png" alt="">
  
          <span>Item 4</span>
  
        </a>
  
      </li>
  
      <li class="load-more__item">
  
        <a href="#!">
  
          <img src="https://radancy.dev/placeholder.png" alt="">
  
          <span>Item 5</span>
  
        </a>
  
      </li>
  
      <li class="load-more__item">
  
        <a href="#!">
  
          <img src="https://radancy.dev/placeholder.png" alt="">
  
          <span>Item 6</span>
  
        </a>
  
      </li>
  
      <li class="load-more__item">
  
        <a href="#!">
  
          <img src="https://radancy.dev/placeholder.png" alt="">
  
          <span>Item 7</span>
  
        </a>
  
      </li>
  
      <li class="load-more__item">
  
        <a href="#!">
  
          <img src="https://radancy.dev/placeholder.png" alt="">
  
          <span>Item 8</span>
  
        </a>
  
      </li>
  
      <li class="load-more__item">
  
        <a href="#!">
  
          <img src="https://radancy.dev/placeholder.png" alt="">
  
          <span>Item 9</span>
  
        </a>
  
      </li>
  
      <li class="load-more__item">
  
        <a href="#!">
  
          <img src="https://radancy.dev/placeholder.png" alt="">
  
          <span>Item 10</span>
  
        </a>
  
      </li>
  
    </ul>
  
  </div>
/*!

  Radancy Component Library: Load More

  Contributor(s): 
  Michael "Spell" Spellacy

  Dependencies: Sass

*/

$base-color: #6F00EF;

.load-more {

  // Assistive Tech Message - Do not remove!

  &__msg {
  clip-path: inset(100%);
  clip: rect(0 0 0 0);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
  }

  &__container {
  list-style: none;
  margin: 0;
  padding: 0;

    @media(min-width: 48.625em) {

      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;

    }

  }

  &__item {
  margin-bottom: 1em;

    @media(min-width: 48.625em) {

      width: 33.3%;

    }

    a {
    display: block;
    margin: .5em;
    padding: .5em;
    }

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

  }

  &__btn {
  background-color: $base-color;
  border: 0;
  color: #fff;
  display: block;
  line-height: normal;
  margin: 0 auto;
  max-width: calc(200rem / 16);
  padding: 1.5em;
  text-align: center;
  text-transform: uppercase;

    &[disabled] {
    opacity: .5;
    }

  }

}
/*!

  Radancy Component Library: Load More

  Contributor(s):
  Michael "Spell" Spellacy

*/

(() => {

  "use strict";

  const initLoadMore = () => {

    // Display which version is in use via console:

    console.log("%cLoad More%cv1.0.0", "background: #2d2d2d; color: #fff; padding: 6px 10px; border-radius: 16px 0 0 16px; font-weight: 600;" , "background: #6e00ee; color: #fff; padding: 6px 10px; border-radius: 0 16px 16px 0; font-weight: 600;");

    // Classes, data attributes, states, and strings.

    const loadMoreClass = ".load-more";
    const loadMoreItemClass = ".load-more__item";
    const loadMoreMsgClass = ".load-more__msg";
    const loadMoreBtnName = "load-more__btn";
    const loadMoreBtnTxt = "Load More";
    const loadMoreBtnFin = "All Done!";
    const loadMoreNewItemTxt = " new items have been loaded.";
    const loadMoreNewItemSingleTxt = " new item has been loaded.";
    const loadMoreComplete = "All content has been loaded.";
    const loadMoreDelay = 500;
    const loadMoreDefault = 3;
    const focusableSelectors = "a, audio, button, input, select, video";
    const loadMoreContainers = document.querySelectorAll(loadMoreClass);

    loadMoreContainers.forEach((container) => {

      const loadMoreShow = container.dataset.loadMoreShow ? parseInt(container.dataset.loadMoreShow) : loadMoreDefault;

      // Hide all items after nth item.

      const items = container.querySelectorAll(loadMoreItemClass);

      items.forEach((item, i) => {

        if (i >= loadMoreShow) {

          item.setAttribute("hidden", "");

        }

      });

      // Add button.

      const loadMoreBtn = document.createElement("button");

      loadMoreBtn.classList.add(loadMoreBtnName);
      loadMoreBtn.textContent = loadMoreBtnTxt;

      container.append(loadMoreBtn);

      // Button action: update message when items are displayed.

      loadMoreBtn.addEventListener("itemsDisplayed", (e) => {

        const totalCount = e.detail.totalCount;
        const hiddenItems = container.querySelectorAll(`${loadMoreItemClass}[hidden]`);
        const msg = container.querySelector(loadMoreMsgClass);

        if (!hiddenItems.length) {

          loadMoreBtn.disabled = true;
          loadMoreBtn.textContent = loadMoreBtnFin;

          if (msg) {

            if (totalCount === 1) {

              msg.innerHTML = totalCount + loadMoreNewItemSingleTxt + " " + loadMoreComplete;

            } else {

              msg.innerHTML = totalCount + loadMoreNewItemTxt + " " + loadMoreComplete;

            }

          }

        }

      });

      // Button click: reveal next batch of items.

      loadMoreBtn.addEventListener("click", () => {

        const hiddenItems = container.querySelectorAll(`${loadMoreItemClass}[hidden]`);
        const itemsToLoad = container.dataset.loadMoreShow ? parseInt(container.dataset.loadMoreShow) : loadMoreDefault;
        const itemsToReveal = Array.from(hiddenItems).slice(0, itemsToLoad);
        const msg = container.querySelector(loadMoreMsgClass);

        itemsToReveal.forEach((item) => {

          item.removeAttribute("hidden");

        });

        const totalItems = itemsToReveal.length;

        if (msg) {

          msg.innerHTML = totalItems + loadMoreNewItemTxt;

        }

        // Focus first focusable element within newly revealed items.

        let firstFocusable = null;

        for (const item of itemsToReveal) {

          firstFocusable = item.querySelector(focusableSelectors);

          if (firstFocusable) break;

        }

        if (firstFocusable) {

          firstFocusable.focus();

        }

        // Dispatch custom event.

        loadMoreBtn.dispatchEvent(new CustomEvent("itemsDisplayed", {

          detail: { totalCount: totalItems }
  
        }));

        // Remove message after delay.

        setTimeout(() => {

          document.querySelectorAll(loadMoreMsgClass).forEach((msgEl) => {

            msgEl.innerHTML = "";

          });

        }, loadMoreDelay);

      });

    });

  };

  initLoadMore();

})();

Properties Anchor (Properties)

Use the following properties to configure this component.

Attribute Applies To Note Description
data-load-more-max .load-more Number, Optional
Used to set the maximum number of items first shown on page load and items shown when the "Load More" button is pressed. The default is 3.

Class Applies To Note Description
.load-more div, section Mandatory
Used on the parent element that wraps your list.
.load-more__btn button Component
Used on the button that loads more content.
.load-more__container ul, ol Mandatory
Used on the list element that wraps your list items.
.load-more__item li Mandatory
Used on the list items that wrap your content.
.load-more__msg div Mandatory
Used to alert assistive technology users that a change has occured on the page after clicking .load-more__btn.

Report Issues

Find a bug? Want a new feature? Report it on JIRA. You're so awesome!