DataTables Filtering for Accented Characters

03 May 2023

See also the older discussion Customizing DataTables Global Search. The approach shown below provides a different way to handle the global search.

There are two parts to this:

  1. Code to manage accented text.

  2. Code to customize how the DataTables global search works.

Accented Text

Here is the JavaScript:

JavaScript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function neutralize( text ) {
  // NFD    = canonical decomposition - https://unicode.org/reports/tr15/#Norm_Forms
  // /g     = regex global flag
  // /u     = regex Unicode flag
  // \p{Mn} = regex class for nonspacing marks (diacritics, etc.) -
  // https://www.fileformat.info/info/unicode/category/Mn/list.htm
  // https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt
  return text.trim().toLowerCase()
    .normalize('NFD') // separates nonspacing marks from letters (the bytes)
    .replace(/\p{Mn}/gu, '') // removes nonspacing marks (the bytes)
    // and whatever additional custom steps you want to take:
    .replace(/\xA0/g, ' '); // e.g. non-breaking space -> regular space
}

The NFD (canonical decomposition) mode takes a character such as é and splits it into separate glyphs (symbols). So in this case, these are:

  • Latin Small Letter E (U+0065)
  • Combining Acute Accent (U+0301)

The replace regular expression removes all of the glyphs which belong to the Unicode Mn class. These are the nonspacing marks glyphs - including our combining acute accent.

So, we separate the accents from their characters so that we can then remove them.

This converts é into e.

If we apply this function to the search term provided by the user and the data being searched, then we are comparing similarly “neutralized” strings of text.

The Global Search

We need to switch off the default global search behavior - which would otherwise run first, before any of our custom searching (well, actually, filtering) logic is executed:

JavaScript
1
$('.dataTables_filter input').off()...

A Full Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Demo</title>
        <script src="https://code.jquery.com/jquery-3.6.0.js"></script>
        <script src="https://cdn.datatables.net/1.12.1/js/jquery.dataTables.js"></script>
        <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.12.1/css/jquery.dataTables.css">
        <link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css">
    </head>
    <body>
        <div style="margin: 20px;">
            <table id="example" class="display dataTable cell-border" style="width:100%">
                <thead>
                    <tr>
                        <th>Name</th>
                        <th>Position</th>
                        <th>Office in Country</th>
                        <th>Age</th>
                        <th>Start date</th>
                        <th>Salary</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>Amélie Nixon</td>
                        <td>System&nbsp;Architect</td>
                        <td>Edinburgh</td>
                        <td>61</td>
                        <td>2011/04/25</td>
                        <td>$320,800</td>
                    </tr>
                    <tr>
                        <td>Gérard Fête</td>
                        <td>Systέm Architect</td>
                        <td>Edinburgh</td>
                        <td>61</td>
                        <td>2011/04/25</td>
                        <td>$320,800</td>
                    </tr>
                </tbody>
            </table>
        </div>
        <script>
            $(document).ready(function() {

              var table = $('#example').DataTable({});

              // https://datatables.net/manual/plug-ins/search
              $.fn.dataTable.ext.search.push( function ( settings, searchData ) {
                var searchTerm = neutralize($('.dataTables_filter input').val());
                var found = false;
                searchData.forEach( field => {
                  if ( neutralize(field).includes(searchTerm) ) {
                    found = true;
                  }
                } );
                return found;
              } );

              $('.dataTables_filter input').off().on('keyup', function() {
                table.draw();
              } );

            } );

            function neutralize( text ) {
              return text.trim().toLowerCase().normalize('NFD').replace(/\p{Mn}/gu, '');
            }

        </script>
    </body>
</html>