Blog
How to Build a Load More Button with JavaScript
A load more button reveals the next set of items without opening another page. In this tutorial, you’ll build an accessible, responsive card grid with plain HTML, CSS, and vanilla JavaScript. The example shows four cards at first, then adds four more each time the button is activated.
Quick answer: Keep all items in the HTML, hide the later items with the hidden attribute, and remove that attribute from the next batch when the user clicks a button. This approach needs no library and works for a small, already-loaded list.
Try the Live DemoDownload Source ZIP
How the load more pattern works
The page starts with every card in the document, but cards after the first batch are hidden. JavaScript tracks how many are visible. A button click reveals the next batch, updates a short screen-reader status message, and hides the button when no hidden cards remain.
This client-side example is best for a modest list whose content can load with the page. For a large catalogue, use server-side pagination or fetch the next page from an API so the browser does not need to download every item up front.
1. Add the cards and button in HTML
Use a semantic section for the group and an article for each item. The native hidden attribute keeps later cards out of the visual layout and accessibility tree until they are revealed. The button’s aria-controls points to the card group, and a polite live region reports how many cards are visible.
2. Style the grid for different screen sizes
CSS Grid creates two columns on larger screens and one column on narrow screens. The button has a visible keyboard focus ring. Keep the text concise and make each card understandable on its own; the example uses descriptive content rather than repeated placeholder paragraphs.
3. Reveal the next batch with JavaScript
Start by counting cards that are not hidden. On activation, calculate the next stopping point with Math.min(), reveal only that slice, and update the count. When the visible count reaches the total, hide the button. This avoids an empty click and makes the final state clear.
Try the interactive demo
Click Load more to reveal four more cards. The status text updates after each click, and the control disappears when all eight cards are shown.
Customize the batch size
Change batchSize in the JavaScript to show a different number of cards per click. If the initial number should differ from the batch size, set the initial visible cards in the HTML and keep the JavaScript count in sync. You can replace each sample card with a post preview, product, gallery item, or other repeated content.
Common problems
- The button does nothing: Check that the script loads after the markup or uses
defer, and confirm the selectors match the HTML classes. - Hidden cards appear too early: Make sure later cards have the
hiddenattribute and that CSS does not override the browser’s hidden display behavior. - The button remains after the last item: Compare the visible count with the total card count after every reveal.
- There is a long list: Prefer pagination or load data from a server in smaller pages instead of placing every item in the initial HTML.
Frequently asked questions
Does this example need jQuery?
No. It uses standard browser JavaScript to select cards, handle a click, and update the DOM.
Is a load more button the same as infinite scroll?
No. A button lets visitors choose when to reveal more and provides a clear keyboard-accessible control. Infinite scroll loads content automatically as the visitor moves down the page.
Will this load more items from a database?
No. This demo reveals items already present in the page. To fetch new items from a database, connect the button to a paginated API or server endpoint and handle loading, errors, and empty results.
Use the live example to see each state, then download the source ZIP to adapt the HTML, stylesheet, and JavaScript for your project.
INTERACTIVE EXAMPLE · VANILLA JAVASCRIPT
Load more content
Reveal four more cards at a time. No library or page reload required.
- 01
Plan a small project
Break a big idea into clear tasks and decide what to build first.
- 02
Write useful HTML
Use semantic elements to make page content easier to understand.
- 03
Style with CSS
Create a flexible layout that stays readable on every screen.
- 04
Add a small script
Reveal the next set of items while keeping the page simple.
- 05
Check keyboard access
Make sure every control works without a mouse.
- 06
Keep labels clear
Use concise text so visitors know what each button does.
- 07
Test narrow screens
Check that cards fit without horizontal scrolling.
- 08
Ship the improvement
Test the full interaction before publishing your page.
Showing 4 of 8 cards
<section class="demo">
<h2>Latest articles</h2>
<ul class="card-grid" aria-label="Latest articles">
<li class="card">Article one</li>
<li class="card">Article two</li>
<li class="card">Article three</li>
<li class="card">Article four</li>
<li class="card" hidden>Article five</li>
<li class="card" hidden>Article six</li>
</ul>
<button class="load-more" type="button">Load more</button>
<p class="status" aria-live="polite">Showing 4 of 6 articles</p>
</section>
.card-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
margin: 0;
padding: 0;
list-style: none;
}
.card {
padding: 19px;
border: 1px solid #e1e9f7;
border-radius: 15px;
background: #fff;
}
.card[hidden] {
display: none !important;
}
.load-more:focus-visible {
outline: 3px solid #f4b740;
outline-offset: 3px;
}
@media (max-width: 560px) {
.card-grid {
grid-template-columns: 1fr;
}
}
const grid = document.querySelector('.card-grid');
const cards = [...grid.querySelectorAll('.card')];
const button = document.querySelector('.load-more');
const status = document.querySelector('.status');
const batchSize = 4;
let visibleCount = cards.filter((card) => !card.hidden).length;
button.addEventListener('click', () => {
const nextCount = Math.min(visibleCount + batchSize, cards.length);
cards.slice(visibleCount, nextCount).forEach((card) => {
card.hidden = false;
});
visibleCount = nextCount;
status.textContent = 'Showing ' + visibleCount + ' of ' + cards.length + ' cards';
if (visibleCount === cards.length) button.hidden = true;
});