How can I make my filter search code more efficient?
1) Avoid unnecessary document.querySelector and document.querySelectorAll. Store its results if you sure there won't be any changes.

Element searching in the DOM is relatively hard operation (it is extremely optimized, but still). So you should avoid it if you can.

You've already done a lot for that, but I still can see unsaved document.querySelector(".page-header.cf")

2) Use event delegation pattern.

You don't have to add event listeners to each element on the page. Especially if they are in the same container.



const parent = document.querySelector('#parent');

parent.addEventListener('click', (e) =&gt; {
  const target = e.target.closest('a');
  
  if (!target) return;
  
  if (target.matches('.active')) {
    target.classList.remove('active');
    
    resetPage();
  } else {
    target.classList.add('active');
    
    const page = target.textContent;
    
    displayPage(page);
  }
});
&lt;div id="parent"&gt;
  &lt;a class="page-number"&gt;1&lt;/a&gt;
  &lt;a class="page-number"&gt;1&lt;/a&gt;
&lt;/div&gt;




As a bonus, you don't have to add event listeners on newly created links or remove it from removed links.

3) Do not modify elements content as HTML string if you can avoid it. 

In your case you can move li.no-results outside of studentList and show/hide it with display: none/block property. Or at least remove/append this element as a node, not as HTML-string. It is much faster.

4) Use debounce.

You don't need to trigger the search on each keyup. You need to trigger it only when user stops typing. So when you have event series with, let's say, 200 ms interval, you need to trigger search only for the last one. You can use lodash/debounce for that or write your own implementation

5) Learn how to use Chrome Profiling Tool
It helps to find bottlenecks of your app and fix them.