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!