JSFiddle - React, Tailwind, and code Playground

by joshmoto

HTML

<div id="faq">

  <input type="search" placeholder="Filter FAQ" />
  
  <ul class="repeater">
    <li>
      <div data-question>Whats the best way to search repeater fields?</div>
      <div data-answer>Use some jQuery to filter repeater fields.</div>
    </li>
    <li>
      <div data-question>Why do we use Advanced Custom Fields?</div>
      <div data-answer>Because its awesome!</div>
    </li>
    <li>
      <div data-question>Is this method fast?</div>
      <div data-answer>Yes it works instantly on every keyup.</div>
    </li>
    <li>
      <div data-question>Why do we use Wordpress?</div>
      <div data-answer>Because it's a great content management system!</div>
    </li>
    <li class="filter-no-results">
      No results found in repeater fields.
    </li>
  </ul>

</div>

CSS

#faq {
  padding: 1rem;
}

INPUT[type="search"] {
  margin-bottom: 1rem;
}

.repeater LI {
  margin-bottom: 1rem;
}

[data-question]::before {
  content: 'Q. ';
  font-weight: bold;
}

[data-answer]::before {
  content: 'A. ';
  font-weight: bold;
}

.filter-visible {
  display: block;
}

.filter-hidden {
  display: none;
}

.filter-no-results {
  display: none;
}

JavaScript

// faq repeater field filter 
$('#faq').on('keyup', 'INPUT[type="search"]', function(event) {

  // get our elements
  let $faq = $(event.delegateTarget);
  
  // get the search filter value
  let search = $(this).val().replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
  
  // get the repeater list in faq object
  let $repeater = $('.repeater', $faq);
  
  // items visible counter
  let itemsVisible = 0;

  // return false early if we dont have a list
  if ($repeater.length < 1) return false;

  // loop through each item in the repeater list
  $("LI:not('.filter-no-results')", $repeater).each(function(key, item) {
  
    // strip all mark tags from list item html
    $(this).html($(this).html().replaceAll(/<(\/?|\!?)(mark)>/g, ""));
   
    // store our q and a text
    let text = $(this).text();

    // check if the item is visible using regular expression match
    let itemVisible = text.match(new RegExp(search, 'i'));
    
    // remove these classes
    $(item).removeClass('filter-visible filter-hidden');

    // check if we have a match
    $(item).addClass('filter-' + (itemVisible ? 'visible' : 'hidden'));
    
    // for each div inside the list item
    $('div',this).each(function(){
    
      // highlight the matched search text by wrapping it with a mark tag
    	let newText = $(this).html().replace(itemVisible, '<mark>' + itemVisible + '</mark>');
      
      // update the html with new text
    	$(this).html(newText);
      
    });

    // if item is visible, increment our count
    if (itemVisible) ++itemsVisible;

  });

  // check if we have no items visible then show hide no results message
  if (itemsVisible === 0) {
    $('LI.filter-no-results', $repeater).show();
  } else {
    $('LI.filter-no-results', $repeater).hide();
  }

});