Adding a custom search filter to jQuery DataTables

jQuery DataTables is the premier solution for adding sorting/searching/paging to a static HTML table. However, adding a second search can seem more troublesome than it's worth, as there are a few gotchas you need to avoid.

Start here

The documentation contains a good Custom filtering - range search example that adds two new INPUT elements. These inputs filter a column in the table by min/max numbers. However…

There is one key takeaway from this example though. $ is an array of functions that is run for each row of data. If a function returns false for a row, that row is hidden on the table.

Also, be advised that the function for the DataTables default search input always runs before your custom functions. This means you can't just repurpose the value of the default search input when searching inside ranges. For example, say a colum of your table lists temperature ranges for a set of days. If you want to search the table for temperature values inside the listed ranges, you'll need to add your own custom INPUT element where you can enter your search temperature. If you enter a temperature into the default search INPUT, only temperature values that directly appear in the table will be displayed.

Add an INPUT element dynamically

We can add a new INPUT element to the page dynamically after we initialize the DataTable by doing the following:

// Get the table element and initialize it
let table = $('#myTable'),
    settings = {
      // Assign your settings here
    dataTable = table.DataTable(settings);

// Now that the DataTable is initialized, the plugin has finished making DOM
// modifications. Let's search for their INPUT and add our own before it.
let tableId = table.attr('id'),
    searchInput = table
    ourInput = $(document.createElement('input'))
        type: 'search',
        'class': 'form-control form-control-sm',
        'aria-controls': tableId,

There are a few important gotchas to consider:

Listen for keyup events and filter the table

Now that we have our new INPUT element, we can listen for keyup events and tell the DataTable to redraw, filtering by the new input value:

let query = undefined;
ourInput.on('keyup', () => {
  // Store the value of our INPUT in a higher scope so the filter function below
  // can see the value. This way we do a DOM request for the value of the INPUT
  // once, instead of in each execution of the filter function (which runs for
  // each row of the table).
  query = ourInput.val();
  // If the INPUT is empty, we want to show all results, so store a value we can
  // easily test for as empty later on
  if (query === '') {
    query = undefined;
  // Redraw the DataTable, which then also runs all the
  // $ functions

// This is our filter that runs each time the table is redrawn
function filterDataTable(settings, data, dataIndex) {
  // When undefined that means our INPUT is empty, so show all results
  if (query === undefined) {
    return true;
  // We only want to use our INPUT on the TABLE where it is displayed, not
  // other DataTables on the page, so we need to check that the ID of the table
  // being drawn matches the tableId we stored in the last code block
  if (settings.sTableId !== tableId) {
    return true;
  // Now we can run our own custom search logic. The below searches for exact
  // strings on the first column in the table. This alone isn't too useful, so
  // replace this portion with your own logic.
  let columnIndex = 0;
  return data[columnIndex] === query;
// Add our filter to the list of filters that is run

Put it all together

I originally got turned onto this problem when a client asked if we could search inside a list of IP ranges. Their DataTable contained a column with IP ranges specified in CIDR notation. The npm package netmask can handle the CIDR notation, so we just needed to wire up netmask into a custom DataTables search filter. Along the way I hit every single gotcha listed above :-p

AWS publishes a list of their public IP ranges which are loaded into the example below. The snippets of code above create and drive the "Search by IP" filter.

Open in new tab