Responsive card grid with a blue Load More button and JavaScript code
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 hidden attribute 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.

Showing 4 of 8 cards

HTML markup
<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>
CSS styles
.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;
  }
}
JavaScript behavior (vanilla)
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;
});