Js filter a multiple page list

I have a working filtered list using JS, but the amount of list elements is growing. So I need to divide the list in pages, but for the filter to keep working for the whole list, even if the list element is not showing because it is in another page.

I’ve seen how to make a “previous” and “next” buttons for list, but it breaks down the filter js, because it consists basically of placing the contents on different divs, but the filter will only filter the first one.

This is my HTML now:

  <input type="text" id="barraBusqueda" onkeyup="buscar()" placeholder="Buscar artículos">
  <ul id="articulos">
    <li><a href="/es/blog/1.html">Article 1</a></li>
    <li><a href="/es/blog/2.html">Article 2</a></li>
    <li><a href="/es/blog/3.html">Article 3</a></li>
    <li><a href="/es/blog/4.html">Article 4</a></li>
    <li><a href="/es/blog/5.html">Article 5</a></li>
    <li><a href="/es/blog/6.html">Article 6</a></li>
    <li><a href="/es/blog/7.html">Article 7</a></li>
    <li><a href="/es/blog/8.html">Article 8</a></li>
    <li><a href="/es/blog/9.html">Article 9</a></li>
    <li><a href="/es/blog/10.html">Article 10</a></li>

And my JS:

function buscar() {
  // Declare variables
  var input, filter, ul, li, a, i, txtValue;
  input = document.getElementById("barraBusqueda");
  filter = input.value.toUpperCase();
  ul = document.getElementById("articulos");
  li = ul.getElementsByTagName("li");

  // Loop through all list items, and hide those who don't match the search query
  for (i = 0; i < li.length; i++) {
    a = li[i].getElementsByTagName("a")[0];
    txtValue = a.textContent || a.innerText;
    if (txtValue.toUpperCase().indexOf(filter) > -1) {
      li[i].style.display = "";
    } else {
      li[i].style.display = "none";

It works fine, but all the elements have to be showing, and I don’t want an eternal scroll through dozens of list items.

Goal would be that the browser only displays 5 list items at a time, with a next and previous button to navigate through them, but that the filter considers all the list items, even those that are in other pages.


Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

I would recommend to separate the data from the representation. This makes it easier to combine filtering and paging.

As a first step I would create an array of objects describing the list of entries. On this array you can perform filtering. Secondly, I would write a function which renders the list entries. This way you don’t have to hide HTML elements, you only render those that match your filter and/or page.

Please take a look at this (incomplete) working example:

// The maximum size of a single page
const pageSize = 5;

// All list entries (unfiltered)
const data = [
   { name: 'Article 1', url: '/es/blog/1.html' },
   { name: 'Article 2', url: '/es/blog/2.html' },
   { name: 'Article 3', url: '/es/blog/3.html' },
   { name: 'Article 4', url: '/es/blog/4.html' },
   { name: 'Article 5', url: '/es/blog/5.html' },
   { name: 'Article 6', url: '/es/blog/6.html' },
   { name: 'Article 7', url: '/es/blog/7.html' },
   { name: 'Article 8', url: '/es/blog/8.html' },
   { name: 'Article 9', url: '/es/blog/9.html' },
   { name: 'Article 10', url: '/es/blog/10.html' },
   { name: 'Article 11', url: '/es/blog/11.html' },
   { name: 'Article 12', url: '/es/blog/12.html' },
   { name: 'Article 13', url: '/es/blog/13.html' },
   { name: 'Article 14', url: '/es/blog/14.html' },

// The filtered data; initially equal to `data`; 
// modified by function filter()
let filteredData = data;

// The current page index
let currentPage = 0;

// Adds/removes the `disabled` attribute from the element by
// specified ID according to the `disabled` flag
function updateButtonState(id, disabled) {
  const button = document.getElementById(id);
  if (disabled) {
    button.setAttribute('disabled', 'true');
  else {

// Updates the states of the Previous/Next buttons
function updateButtonStates() {
  updateButtonState('btn-prev', currentPage === 0);
  updateButtonState('btn-next', (currentPage + 1) * pageSize >= filteredData.length);

// Filters the `data` array according to the given text
function filter(text) {
  filteredData = data.filter(entry => entry.name.includes(text));

// Renders a single page, using the `filteredData` array
function renderPage(pageNo) {
  currentPage = pageNo;

  const elList = document.getElementById('list');
  elList.innerHTML = '';

  const offset = pageNo * pageSize;
  for (let i = offset; i < offset + pageSize && i < filteredData.length; i++) {
    const entry = filteredData[i];
    const li = elList.appendChild(document.createElement('li'));
    const anchor = li.appendChild(document.createElement('a'));
    anchor.innerHTML = entry.name;
    anchor.href = entry.url;

// Render first page initially
<input type="text" onkeyup="filter(this.value)">

<ul id="list">

<button id="btn-prev" onclick="renderPage(currentPage - 1)">Previous</button>
<button id="btn-next" onclick="renderPage(currentPage + 1)">Next</button>

Test it by entering 1 into the search field.

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Notify of

Inline Feedbacks
View all comments
Would love your thoughts, please comment.x