DataTables search child row content


In order for jQuery DataTables to search child rows you need to add data displayed in the child rows to the main table as hidden columns.

For example, you can add hidden column for extn data property using columns.visible option as shown below:


    "columns": [
            "class":          'details-control',
            "orderable":      false,
            "data":           null,
            "defaultContent": ''
        { "data": "name" },
        { "data": "position" },
        { "data": "office" },
        { "data": "salary" },
        { "data": "extn", "visible": false }            




See this jsFiddle for code and demonstration. Search for 5407 and the first row will be shown even though data appears only in child row.

This is quite an old thread, and the accepted answer does work, but I wanted to propose an alternate solution.

I was having the same issue not being able to search within child rows, and my solution was to make a hidden <td> on the end of my table that contained the data in the child rows - this way, the indexer sees it but the user does not.

For the limited HTML, I added a new column:

<th class="hidden">Data</th>

Then, within the DataTables call:

//Within var table = $('#table').DataTable( {....
columns : [
        //{ className : 'details-control'},
        { data : 'a' }, //a-e are the columns I want the user to see.
        { data : 'b' },
        { data : 'c' },
        { data : 'd' },
        { data : 'e' },            
        // this last one is my "index helper"
        { data : 'comments',
          render : function(data, type, full, meta) {
            return full.f + full.g + full.h + full.i;

Then you just need to hide this column. You could do this either through DataTables' recommended method:

or through the method I chose:

"createdRow" : function (row,data,index) {

//and the css...
.hidden {
 visibility: hidden;

You're left with one <td> at the end of your table that contains everything from the child rows, but it's invisible, and it works with the search box/filter thingy.

I have to ask : What make you believe you can search in child row content you are injecting dynamically only when the child rows are shown? And how should a column() search could cover content from other rows, ever?

When this said, there is of course a workaround. Instead of creating the child row content over and over, keep it in an array :

var details = [];

Now, when you are initialising the table, you initialise the child row content as well :

columns: [{
   className: 'details-control',
   orderable: false,
   data: null,
   defaultContent: '',
   render: function(data, type, row, meta) {  
      details[meta.row] = format(data);

In the format() function, add a class to the Extension Number field for easy access :

'<td class="extNo">' + d.extn + '</td>' +

When you show child rows, insert the prerendered content from details[] instead of calling format() :

if (row.child.isShown()) {
} else {

Create a filter that returns only rows which have a details[] child row holding a certain Extension Number :

function filterByDetailsExtNo(extNo) {
    function(settings, data, dataIndex) {
       return $(details[dataIndex]).find('.extNo').text() == extNo;

Use that custom filter instead of the column() search in your input handlers :

table.columns().every( function () {
    $( 'input', this.footer() ).on( 'keyup change', function () {

forked fiddle ->

Update. To apply the above filter to the general searchbox :

$('.dataTables_filter input')
   .on('keyup', function() {

yet another forked fiddle ->

Last example. Combine details search and "native" search

function filterByDetailsExtNoAndInput(term) {
        function(settings, data, dataIndex) {
            if ($(details[dataIndex]).find('.extNo').text() == term) return true;
            for (var i=0;i<data.length;i++) {
                if (data[i].toLowerCase().indexOf(term.toLowerCase())>=0) {
                    return true
            return false;

fiddle ->