Repository: gregnb/mui-datatables
Pull request #613 (2019-05-10 20:14:42)

Single grid column for single filter
When there is only a single filter active in the columns config, use a single column for the filter grid list columns. This will allow the filter to take up 100% of the filter popover width.

Fixes: #604 

coveralls: 
[![Coverage Status](https://coveralls.io/builds/23318476/badge)](https://coveralls.io/builds/23318476)

Coverage decreased (-0.03%) to 77.022% when pulling **fa8ca73930bb12dd7515b77820f7cb3044243f53 on nathancharles:filterWidths** into **267c4cdb3a95fa48bc999beb786612f4dd215f59 on gregnb:master**.


Patch:
diff --git a/README.md b/README.md
index a974c1b..b7040ac 100644
--- a/README.md
+++ b/README.md
@@ -147,6 +147,7 @@ The component accepts the following props:
 |**`customToolbar`**|function||Render a custom toolbar
 |**`customToolbarSelect`**|function||Render a custom selected rows toolbar. `function(selectedRows, displayData, setSelectedRows) => void`
 |**`customFooter`**|function||Render a custom table footer. `function(count, page, rowsPerPage, changeRowsPerPage, changePage) => string`&#124;` React Component`
+|**`customRowRender `**|function||Override default row rendering with custom function. `customRowRender(data, dataIndex, rowIndex) => React Component`
 |**`customSort`**|function||Override default sorting with custom function. `function(data: array, colIndex: number, order: string) => array`
 |**`customSearch `**|function||Override default search with custom function. `customSearch(searchQuery: string, currentRow: array, columns: array) => boolean`
 |**`elevation`**|number|4|Shadow depth applied to Paper component
@@ -160,6 +161,7 @@ The component accepts the following props:
 |**`sort`**|boolean|true|Enable/disable sort on all columns
 |**`filter`**|boolean|true|Show/hide filter icon from toolbar
 |**`search`**|boolean|true|Show/hide search icon from toolbar
+|**`searchText`**|string||Initial search text
 |**`print`**|boolean|true|Show/hide print	 icon from toolbar
 |**`download`**|boolean|true|Show/hide download icon from toolbar
 |**`downloadOptions`**|object||Options to change the output of the CSV file. Default options: `{filename: 'tableDownload.csv', separator: ','}`
@@ -209,6 +211,7 @@ const columns = [
 |:--:|:-----|:--|:-----|
 |**`display`**|string|'true'|Display column in table. `enum('true', 'false', 'excluded')`
 |**`empty`**|boolean|false|This denotes whether the column has data or not (for use with intentionally empty columns)
+|**`viewColumns`**|boolean|true|Allow user to toggle column visibility through 'View Column' list
 |**`filterList`**|array||Filter value list [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/column-filters/index.js)
 |**`filterOptions`**|array||Filter options [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/column-filters/index.js)
 |**`customFilterListRender`**|function||Function that returns a string used as the chip label. `function(value) => string` [Example](https://github.com/gregnb/mui-datatables/blob/master/examples/column-filters/index.js)
diff --git a/examples/customize-rows/index.js b/examples/customize-rows/index.js
new file mode 100644
index 0000000..33bf240
--- /dev/null
+++ b/examples/customize-rows/index.js
@@ -0,0 +1,96 @@
+/*
+  See another example of how to use `customRowRender` at
+  https://github.com/Skn0tt/mui-datatables-responsive-demo
+  https://mui-datatables-responsive-demo.skn0tt.now.sh
+*/
+
+import React from 'react';
+import ReactDOM from "react-dom";
+import MuiDataTable from "../../src/";
+
+function YourCustomRowComponent(props) {
+  const { name, cardNumber, cvc, expiry } = props;
+
+  return (
+    <div>
+      <h1>
+        {name}
+      </h1>
+      <p>
+        Number: {cardNumber} <br/>
+        CVC: {cvc} <br/>
+        expiry: {expiry}
+      </p>
+    </div>
+  );
+}
+
+const creditCards = [
+  {
+    name: "Tom Tallis",
+    cardNumber: "5500005555555559",
+    cvc: "582",
+    expiry: "02/24"
+  },
+  {
+    name: "Rich Harris",
+    cardNumber: "4444444444444448",
+    cvc: "172",
+    expiry: "03/22"
+  },
+  {
+    name: "Moby Dixon",
+    cardNumber: "3566003566003566",
+    cvc: "230",
+    expiry: "12/25"
+  }
+];
+
+function Example() {
+  return (
+    <MuiDataTable
+      title="Cards"
+      data={creditCards}
+      columns={[
+        {
+          name: "name",
+          label: "Name",
+        },
+        {
+          name: "cardNumber",
+          label: "Card Number"
+        },
+        {
+          name: "cvc",
+          label: "CVC"
+        },
+        {
+          name: "expiry",
+          label: "Expiry"
+        },
+      ]}
+      options={{
+        selectableRows: "none",
+        responsive: "scroll",
+        customRowRender: data => {
+          const [ name, cardNumber, cvc, expiry ] = data;
+          
+          return (
+            <tr key={cardNumber}>
+              <td colSpan={4} style={{ paddingTop: "10px"}}>
+                <YourCustomRowComponent
+                  name={name}
+                  cardNumber={cardNumber}
+                  cvc={cvc}
+                  expiry={expiry}
+                />
+              </td>
+            </tr>
+          );
+        },
+      }}
+    />
+  );
+}
+
+ReactDOM.render(<Example />, document.getElementById("app-root"));
diff --git a/examples/customize-search/index.js b/examples/customize-search/index.js
index a79b781..d9bef72 100644
--- a/examples/customize-search/index.js
+++ b/examples/customize-search/index.js
@@ -1,101 +1,96 @@
-import React from "react";
-import ReactDOM from "react-dom";
-import MUIDataTable from "../../src/";
+import React from 'react';
+import ReactDOM from 'react-dom';
+import MUIDataTable from '../../src/';
 
 class Example extends React.Component {
-
   render() {
-
     const columns = [
       {
-        name: "Name",
+        name: 'Name',
         options: {
           filter: true,
           display: 'excluded',
-        }
-      },      
+        },
+      },
       {
-        label: "Modified Title Label",
-        name: "Title",
+        label: 'Modified Title Label',
+        name: 'Title',
         options: {
           filter: true,
-        }
+        },
       },
       {
-        name: "Location",
+        name: 'Location',
         options: {
           filter: false,
-        }
+        },
       },
       {
-        name: "Age",
+        name: 'Age',
         options: {
           filter: true,
-        }
+        },
       },
       {
-        name: "Salary",
+        name: 'Salary',
         options: {
           filter: true,
-          sort: false
-        }
-      }      
+          sort: false,
+        },
+      },
     ];
 
-
     const data = [
-      ["Gabby George", "Business Analyst", "Minneapolis", 30, "$100,000"],
-      ["Aiden Lloyd", "Business Consultant", "Dallas",  55, "$200,000"],
-      ["Jaden Collins", "Attorney", "Santa Ana", 27, "$500,000"],
-      ["Franky Rees", "Business Analyst", "St. Petersburg", 22, "$50,000"],
-      ["Aaren Rose", "Business Consultant", "Toledo", 28, "$75,000"],
-      ["Blake Duncan", "Business Management Analyst", "San Diego", 65, "$94,000"],
-      ["Frankie Parry", "Agency Legal Counsel", "Jacksonville", 71, "$210,000"],
-      ["Lane Wilson", "Commercial Specialist", "Omaha", 19, "$65,000"],
-      ["Robin Duncan", "Business Analyst", "Los Angeles", 20, "$77,000"],
-      ["Mel Brooks", "Business Consultant", "Oklahoma City", 37, "$135,000"],
-      ["Harper White", "Attorney", "Pittsburgh", 52, "$420,000"],
-      ["Kris Humphrey", "Agency Legal Counsel", "Laredo", 30, "$150,000"],
-      ["Frankie Long", "Industrial Analyst", "Austin", 31, "$170,000"],
-      ["Brynn Robbins", "Business Analyst", "Norfolk", 22, "$90,000"],
-      ["Justice Mann", "Business Consultant", "Chicago", 24, "$133,000"],
-      ["Addison Navarro", "Business Management Analyst", "New York", 50, "$295,000"],
-      ["Jesse Welch", "Agency Legal Counsel", "Seattle", 28, "$200,000"],
-      ["Eli Mejia", "Commercial Specialist", "Long Beach", 65, "$400,000"],
-      ["Gene Leblanc", "Industrial Analyst", "Hartford", 34, "$110,000"],
-      ["Danny Leon", "Computer Scientist", "Newark", 60, "$220,000"],
-      ["Lane Lee", "Corporate Counselor", "Cincinnati", 52, "$180,000"],
-      ["Jesse Hall", "Business Analyst", "Baltimore", 44, "$99,000"],
-      ["Danni Hudson", "Agency Legal Counsel", "Tampa", 37, "$90,000"],
-      ["Terry Macdonald", "Commercial Specialist", "Miami", 39, "$140,000"],
-      ["Justice Mccarthy", "Attorney", "Tucson", 26, "$330,000"],
-      ["Silver Carey", "Computer Scientist", "Memphis", 47, "$250,000" ],
-      ["Franky Miles", "Industrial Analyst", "Buffalo", 49, "$190,000"],
-      ["Glen Nixon", "Corporate Counselor", "Arlington", 44, "$80,000"],
-      ["Gabby Strickland", "Business Process Consultant", "Scottsdale", 26, "$45,000"],
-      ["Mason Ray", "Computer Scientist", "San Francisco", 39, "$142,000"]
+      ['Gabby George', 'Business Analyst', 'Minneapolis', 30, '$100,000'],
+      ['Aiden Lloyd', 'Business Consultant', 'Dallas', 55, '$200,000'],
+      ['Jaden Collins', 'Attorney', 'Santa Ana', 27, '$500,000'],
+      ['Franky Rees', 'Business Analyst', 'St. Petersburg', 22, '$50,000'],
+      ['Aaren Rose', 'Business Consultant', 'Toledo', 28, '$75,000'],
+      ['Blake Duncan', 'Business Management Analyst', 'San Diego', 65, '$94,000'],
+      ['Frankie Parry', 'Agency Legal Counsel', 'Jacksonville', 71, '$210,000'],
+      ['Lane Wilson', 'Commercial Specialist', 'Omaha', 19, '$65,000'],
+      ['Robin Duncan', 'Business Analyst', 'Los Angeles', 20, '$77,000'],
+      ['Mel Brooks', 'Business Consultant', 'Oklahoma City', 37, '$135,000'],
+      ['Harper White', 'Attorney', 'Pittsburgh', 52, '$420,000'],
+      ['Kris Humphrey', 'Agency Legal Counsel', 'Laredo', 30, '$150,000'],
+      ['Frankie Long', 'Industrial Analyst', 'Austin', 31, '$170,000'],
+      ['Brynn Robbins', 'Business Analyst', 'Norfolk', 22, '$90,000'],
+      ['Justice Mann', 'Business Consultant', 'Chicago', 24, '$133,000'],
+      ['Addison Navarro', 'Business Management Analyst', 'New York', 50, '$295,000'],
+      ['Jesse Welch', 'Agency Legal Counsel', 'Seattle', 28, '$200,000'],
+      ['Eli Mejia', 'Commercial Specialist', 'Long Beach', 65, '$400,000'],
+      ['Gene Leblanc', 'Industrial Analyst', 'Hartford', 34, '$110,000'],
+      ['Danny Leon', 'Computer Scientist', 'Newark', 60, '$220,000'],
+      ['Lane Lee', 'Corporate Counselor', 'Cincinnati', 52, '$180,000'],
+      ['Jesse Hall', 'Business Analyst', 'Baltimore', 44, '$99,000'],
+      ['Danni Hudson', 'Agency Legal Counsel', 'Tampa', 37, '$90,000'],
+      ['Terry Macdonald', 'Commercial Specialist', 'Miami', 39, '$140,000'],
+      ['Justice Mccarthy', 'Attorney', 'Tucson', 26, '$330,000'],
+      ['Silver Carey', 'Computer Scientist', 'Memphis', 47, '$250,000'],
+      ['Franky Miles', 'Industrial Analyst', 'Buffalo', 49, '$190,000'],
+      ['Glen Nixon', 'Corporate Counselor', 'Arlington', 44, '$80,000'],
+      ['Gabby Strickland', 'Business Process Consultant', 'Scottsdale', 26, '$45,000'],
+      ['Mason Ray', 'Computer Scientist', 'San Francisco', 39, '$142,000'],
     ];
 
     const options = {
       filter: true,
       filterType: 'dropdown',
       responsive: 'stacked',
+      searchText: 'Computer',
       customSearch: (searchQuery, currentRow, columns) => {
         let isFound = false;
         currentRow.forEach(col => {
           if (col.toString().indexOf(searchQuery) >= 0) {
             isFound = true;
-          }          
+          }
         });
         return isFound;
-      }
+      },
     };
 
-    return (
-      <MUIDataTable title={"ACME Employee list"} data={data} columns={columns} options={options} />
-    );
-
+    return <MUIDataTable title={'ACME Employee list'} data={data} columns={columns} options={options} />;
   }
 }
 
-ReactDOM.render(<Example />, document.getElementById("app-root"));
+ReactDOM.render(<Example />, document.getElementById('app-root'));
diff --git a/package-lock.json b/package-lock.json
index bcf65df..3681f19 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "mui-datatables",
-  "version": "2.0.0-beta.59",
+  "version": "2.1.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/package.json b/package.json
index 6b23a1a..e2a112e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "mui-datatables",
-  "version": "2.1.0",
+  "version": "2.2.0",
   "description": "Datatables for React using Material-UI",
   "main": "dist/index.js",
   "files": [
diff --git a/src/MUIDataTable.js b/src/MUIDataTable.js
index d02112f..eda42cf 100644
--- a/src/MUIDataTable.js
+++ b/src/MUIDataTable.js
@@ -111,6 +111,7 @@ class MUIDataTable extends React.Component {
       customToolbar: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
       customToolbarSelect: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
       customFooter: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
+      customRowRender: PropTypes.func,
       onRowClick: PropTypes.func,
       resizableColumns: PropTypes.bool,
       selectableRows: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['none', 'single', 'multiple'])]),
@@ -130,6 +131,7 @@ class MUIDataTable extends React.Component {
       customSort: PropTypes.func,
       customSearch: PropTypes.func,
       search: PropTypes.bool,
+      searchText: PropTypes.string,
       print: PropTypes.bool,
       viewColumns: PropTypes.bool,
       download: PropTypes.bool,
@@ -375,6 +377,7 @@ class MUIDataTable extends React.Component {
     let sortDirection = null;
 
     const data = status === TABLE_LOAD.INITIAL ? this.transformData(columns, props.data) : props.data;
+    const searchText = status === TABLE_LOAD.INITIAL ? options.searchText : null;
 
     columns.forEach((column, colIndex) => {
       for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {
@@ -461,9 +464,10 @@ class MUIDataTable extends React.Component {
         columns: columns,
         filterData: filterData,
         filterList: filterList,
+        searchText: searchText || prevState.searchText,
         selectedRows: selectedRowsData,
         data: tableData,
-        displayData: this.getDisplayData(columns, tableData, filterList, prevState.searchText),
+        displayData: this.getDisplayData(columns, tableData, filterList, searchText || prevState.searchText),
       }),
       callback,
     );
diff --git a/src/components/Popover.js b/src/components/Popover.js
index 923ce42..29bc6fa 100644
--- a/src/components/Popover.js
+++ b/src/components/Popover.js
@@ -57,7 +57,7 @@ class Popover extends React.Component {
       horizontal: 'center',
     };
 
-    const triggerEl = React.cloneElement(trigger, {
+    const triggerEl = React.cloneElement(<span>{trigger}</span>, {
       key: 'content',
       ref: el => (this.anchorEl = el),
       onClick: () => {
diff --git a/src/components/TableBody.js b/src/components/TableBody.js
index 58924a3..6a0e9df 100644
--- a/src/components/TableBody.js
+++ b/src/components/TableBody.js
@@ -120,53 +120,61 @@ class TableBody extends React.Component {
     return (
       <MuiTableBody>
         {tableRows && tableRows.length > 0 ? (
-          tableRows.map(({ data: row, dataIndex }, rowIndex) => (
-            <React.Fragment key={rowIndex}>
-              <TableBodyRow
-                {...(options.setRowProps ? options.setRowProps(row, dataIndex) : {})}
-                options={options}
-                rowSelected={options.selectableRows !== 'none' ? this.isRowSelected(dataIndex) : false}
-                onClick={this.handleRowClick.bind(null, row, { rowIndex, dataIndex })}
-                id={'MUIDataTableBodyRow-' + dataIndex}>
-                <TableSelectCell
-                  onChange={this.handleRowSelect.bind(null, {
-                    index: this.getRowIndex(rowIndex),
-                    dataIndex: dataIndex,
-                  })}
-                  onExpand={toggleExpandRow.bind(null, {
-                    index: this.getRowIndex(rowIndex),
-                    dataIndex: dataIndex,
-                  })}
-                  fixedHeader={options.fixedHeader}
-                  checked={this.isRowSelected(dataIndex)}
-                  expandableOn={options.expandableRows}
-                  selectableOn={options.selectableRows}
-                  isRowExpanded={this.isRowExpanded(dataIndex)}
-                  isRowSelectable={this.isRowSelectable(dataIndex)}
-                  id={'MUIDataTableSelectCell-' + dataIndex}
-                />
-                {row.map(
-                  (column, columnIndex) =>
-                    columns[columnIndex].display === 'true' && (
-                      <TableBodyCell
-                        {...(columns[columnIndex].setCellProps
-                          ? columns[columnIndex].setCellProps(column, dataIndex, columnIndex)
-                          : {})}
-                        dataIndex={dataIndex}
-                        rowIndex={rowIndex}
-                        colIndex={columnIndex}
-                        columnHeader={columns[columnIndex].label}
-                        print={columns[columnIndex].print}
-                        options={options}
-                        key={columnIndex}>
-                        {column}
-                      </TableBodyCell>
-                    ),
-                )}
-              </TableBodyRow>
-              {this.isRowExpanded(dataIndex) && options.renderExpandableRow(row, { rowIndex, dataIndex })}
-            </React.Fragment>
-          ))
+          tableRows.map((data, rowIndex) => {
+            const { data: row, dataIndex } = data;
+
+            if (options.customRowRender) {
+              return options.customRowRender(row, dataIndex, rowIndex);
+            }
+
+            return (
+              <React.Fragment key={rowIndex}>
+                <TableBodyRow
+                  {...(options.setRowProps ? options.setRowProps(row, dataIndex) : {})}
+                  options={options}
+                  rowSelected={options.selectableRows !== 'none' ? this.isRowSelected(dataIndex) : false}
+                  onClick={this.handleRowClick.bind(null, row, { rowIndex, dataIndex })}
+                  id={'MUIDataTableBodyRow-' + dataIndex}>
+                  <TableSelectCell
+                    onChange={this.handleRowSelect.bind(null, {
+                      index: this.getRowIndex(rowIndex),
+                      dataIndex: dataIndex,
+                    })}
+                    onExpand={toggleExpandRow.bind(null, {
+                      index: this.getRowIndex(rowIndex),
+                      dataIndex: dataIndex,
+                    })}
+                    fixedHeader={options.fixedHeader}
+                    checked={this.isRowSelected(dataIndex)}
+                    expandableOn={options.expandableRows}
+                    selectableOn={options.selectableRows}
+                    isRowExpanded={this.isRowExpanded(dataIndex)}
+                    isRowSelectable={this.isRowSelectable(dataIndex)}
+                    id={'MUIDataTableSelectCell-' + dataIndex}
+                  />
+                  {row.map(
+                    (column, columnIndex) =>
+                      columns[columnIndex].display === 'true' && (
+                        <TableBodyCell
+                          {...(columns[columnIndex].setCellProps
+                            ? columns[columnIndex].setCellProps(column, dataIndex, columnIndex)
+                            : {})}
+                          dataIndex={dataIndex}
+                          rowIndex={rowIndex}
+                          colIndex={columnIndex}
+                          columnHeader={columns[columnIndex].label}
+                          print={columns[columnIndex].print}
+                          options={options}
+                          key={columnIndex}>
+                          {column}
+                        </TableBodyCell>
+                      ),
+                  )}
+                </TableBodyRow>
+                {this.isRowExpanded(dataIndex) && options.renderExpandableRow(row, { rowIndex, dataIndex })}
+              </React.Fragment>
+            );
+          })
         ) : (
           <TableBodyRow options={options}>
             <TableBodyCell
diff --git a/src/components/TableFilter.js b/src/components/TableFilter.js
index 758ffde..a871ff3 100644
--- a/src/components/TableFilter.js
+++ b/src/components/TableFilter.js
@@ -271,6 +271,7 @@ class TableFilter extends React.Component {
   render() {
     const { classes, columns, options, onFilterReset } = this.props;
     const textLabels = options.textLabels.filter;
+    const filterGridColumns = columns.filter(col => col.filter).length === 1 ? 1 : 2;
 
     return (
       <div className={classes.root}>
@@ -294,7 +295,7 @@ class TableFilter extends React.Component {
           </div>
           <div className={classes.filtersSelected} />
         </div>
-        <GridList cellHeight="auto" cols={2}>
+        <GridList cellHeight="auto" cols={filterGridColumns}>
           {columns.map((column, index) => {
             if (column.filter) {
               const filterType = column.filterType || options.filterType;
diff --git a/src/components/TableFilterList.js b/src/components/TableFilterList.js
index 2f4ece6..4fa7df8 100644
--- a/src/components/TableFilterList.js
+++ b/src/components/TableFilterList.js
@@ -23,10 +23,7 @@ class TableFilterList extends React.Component {
     filterListRenderers: PropTypes.array.isRequired,
     /** Columns used to describe table */
     columnNames: PropTypes.PropTypes.arrayOf(
-      PropTypes.oneOfType([
-        PropTypes.string,
-        PropTypes.shape({ name: PropTypes.string.isRequired }),
-      ]),
+      PropTypes.oneOfType([PropTypes.string, PropTypes.shape({ name: PropTypes.string.isRequired })]),
     ).isRequired,
     /** Callback to trigger filter update */
     onFilterUpdate: PropTypes.func,
diff --git a/src/components/TableHeadCell.js b/src/components/TableHeadCell.js
index e662bb7..5521e61 100644
--- a/src/components/TableHeadCell.js
+++ b/src/components/TableHeadCell.js
@@ -33,6 +33,7 @@ const defaultHeadCellStyles = theme => ({
     cursor: 'pointer',
     paddingLeft: '4px',
     height: '10px',
+    position: 'absolute'
   },
   sortActive: {
     color: theme.palette.text.primary,
diff --git a/src/components/TableHeadRow.js b/src/components/TableHeadRow.js
index c8b60e2..afb4380 100644
--- a/src/components/TableHeadRow.js
+++ b/src/components/TableHeadRow.js
@@ -5,7 +5,7 @@ import TableRow from '@material-ui/core/TableRow';
 import { withStyles } from '@material-ui/core/styles';
 
 const defaultHeadRowStyles = {
-  root: {},
+  root: {}
 };
 
 class TableHeadRow extends React.Component {
diff --git a/src/components/TableSearch.js b/src/components/TableSearch.js
index e4e33a7..5329a80 100644
--- a/src/components/TableSearch.js
+++ b/src/components/TableSearch.js
@@ -52,7 +52,7 @@ class TableSearch extends React.Component {
   };
 
   render() {
-    const { classes, options, onHide } = this.props;
+    const { classes, options, onHide, initialSearchText } = this.props;
 
     return (
       <Grow appear in={true} timeout={300}>
@@ -64,6 +64,7 @@ class TableSearch extends React.Component {
             InputProps={{
               'aria-label': options.textLabels.toolbar.search,
             }}
+            defaultValue={initialSearchText}
             onChange={this.handleTextChange}
             fullWidth={true}
             inputRef={el => (this.searchField = el)}
diff --git a/src/components/TableToolbar.js b/src/components/TableToolbar.js
index 59c0829..2380eb9 100644
--- a/src/components/TableToolbar.js
+++ b/src/components/TableToolbar.js
@@ -84,8 +84,8 @@ export const responsiveToolbarStyles = theme => ({
 class TableToolbar extends React.Component {
   state = {
     iconActive: null,
-    showSearch: false,
-    searchText: null,
+    showSearch: Boolean(this.props.options.searchText),
+    searchText: this.props.options.searchText || null,
   };
 
   handleCSVDownload = () => {
@@ -162,13 +162,18 @@ class TableToolbar extends React.Component {
     } = this.props;
 
     const { search, downloadCsv, print, viewColumns, filterTable } = options.textLabels.toolbar;
-    const { showSearch } = this.state;
+    const { showSearch, searchText } = this.state;
 
     return (
       <Toolbar className={classes.root} role={'toolbar'} aria-label={'Table Toolbar'}>
         <div className={classes.left}>
           {showSearch === true ? (
-            <TableSearch onSearch={this.handleSearch} onHide={this.hideSearch} options={options} />
+            <TableSearch
+              initialSearchText={searchText}
+              onSearch={this.handleSearch}
+              onHide={this.hideSearch}
+              options={options}
+            />
           ) : typeof title !== 'string' ? (
             title
           ) : (
@@ -181,7 +186,7 @@ class TableToolbar extends React.Component {
         </div>
         <div className={classes.actions}>
           {options.search && (
-            <Tooltip title={search}>
+            <Tooltip title={search} disableFocusListener>
               <IconButton
                 aria-label={search}
                 buttonRef={el => (this.searchButton = el)}
@@ -216,7 +221,7 @@ class TableToolbar extends React.Component {
             <Popover
               refExit={this.setActiveIcon.bind(null)}
               trigger={
-                <Tooltip title={viewColumns}>
+                <Tooltip title={viewColumns} disableFocusListener>
                   <IconButton
                     aria-label={viewColumns}
                     classes={{ root: this.getActiveIcon(classes, 'viewcolumns') }}
@@ -235,7 +240,7 @@ class TableToolbar extends React.Component {
               refExit={this.setActiveIcon.bind(null)}
               classes={{ paper: classes.filterPaper }}
               trigger={
-                <Tooltip title={filterTable}>
+                <Tooltip title={filterTable} disableFocusListener>
                   <IconButton
                     aria-label={filterTable}
                     classes={{ root: this.getActiveIcon(classes, 'filter') }}


Test patch:
diff --git a/test/MUIDataTable.test.js b/test/MUIDataTable.test.js
index 32bf2c5..7959a1b 100644
--- a/test/MUIDataTable.test.js
+++ b/test/MUIDataTable.test.js
@@ -416,7 +416,12 @@ describe('<MUIDataTable />', function() {
     const columnNames = columns.map(column => ({ name: column.name }));
 
     const mountWrapper = mount(
-      <TableFilterList filterList={filterList} filterListRenderers={filterListRenderers} filterUpdate={() => true} columnNames={columnNames} />,
+      <TableFilterList
+        filterList={filterList}
+        filterListRenderers={filterListRenderers}
+        filterUpdate={() => true}
+        columnNames={columnNames}
+      />,
     );
     const actualResult = mountWrapper.find(Chip);
     assert.strictEqual(actualResult.length, 1);
@@ -432,7 +437,12 @@ describe('<MUIDataTable />', function() {
     const columnNames = columns.map(column => ({ name: column.name }));
 
     const mountWrapper = mount(
-      <TableFilterList filterList={filterList} filterListRenderers={filterListRenderers} filterUpdate={() => true} columnNames={columnNames} />,
+      <TableFilterList
+        filterList={filterList}
+        filterListRenderers={filterListRenderers}
+        filterUpdate={() => true}
+        columnNames={columnNames}
+      />,
     );
     const actualResult = mountWrapper.find(Chip);
     assert.strictEqual(actualResult.length, 1);
@@ -477,7 +487,7 @@ describe('<MUIDataTable />', function() {
   it('should have the proper column name in onFilterChange when applying filters', () => {
     let changedColumn;
     const options = {
-      onFilterChange: column => changedColumn = column
+      onFilterChange: column => (changedColumn = column),
     };
 
     const shallowWrapper = shallow(<MUIDataTable columns={columns} data={data} options={options} />);
diff --git a/test/MUIDataTableBody.test.js b/test/MUIDataTableBody.test.js
index f62cf9d..b908784 100644
--- a/test/MUIDataTableBody.test.js
+++ b/test/MUIDataTableBody.test.js
@@ -207,7 +207,7 @@ describe('<TableBody />', function() {
     const selectRowUpdate = stub();
     const toggleExpandRow = () => {};
 
-    const t = mount(
+    const mountWrapper = mount(
       <TableBody
         data={displayData}
         count={displayData.length}
@@ -224,7 +224,8 @@ describe('<TableBody />', function() {
       />,
     );
 
-    t.find('#MUIDataTableBodyRow-2')
+    mountWrapper
+      .find('#MUIDataTableBodyRow-2')
       .first()
       .simulate('click');
 
@@ -237,7 +238,7 @@ describe('<TableBody />', function() {
     const selectRowUpdate = stub();
     const toggleExpandRow = () => {};
 
-    const t = mount(
+    const mountWrapper = mount(
       <TableBody
         data={displayData}
         count={displayData.length}
@@ -254,7 +255,7 @@ describe('<TableBody />', function() {
       />,
     );
 
-    const props = t
+    const props = mountWrapper
       .find('#MUIDataTableBodyRow-1')
       .first()
       .props();
@@ -263,4 +264,31 @@ describe('<TableBody />', function() {
     assert.isAtLeast(options.setRowProps.callCount, 1);
     assert(options.setRowProps.calledWith(data[1]));
   });
+
+  it("should use 'customRowRender' when provided", () => {
+    const options = { customRowRender: () => <div>Test_Text</div> };
+    const selectRowUpdate = stub();
+    const toggleExpandRow = () => {};
+
+    const mountWrapper = mount(
+      <TableBody
+        data={displayData}
+        count={displayData.length}
+        columns={columns}
+        page={0}
+        rowsPerPage={10}
+        selectedRows={[]}
+        selectRowUpdate={selectRowUpdate}
+        expandedRows={[]}
+        toggleExpandRow={toggleExpandRow}
+        options={options}
+        searchText={''}
+        filterList={[]}
+      />,
+    );
+
+    const html = mountWrapper.html();
+
+    expect(html).to.contain('Test_Text');
+  });
 });
diff --git a/test/MUIDataTableSearch.test.js b/test/MUIDataTableSearch.test.js
index d75245e..ba8e09f 100644
--- a/test/MUIDataTableSearch.test.js
+++ b/test/MUIDataTableSearch.test.js
@@ -19,6 +19,19 @@ describe('<TableSearch />', function() {
     assert.strictEqual(actualResult.length, 1);
   });
 
+  it('should render a search bar with text initialized', () => {
+    const options = { textLabels };
+    const onSearch = () => {};
+    const onHide = () => {};
+
+    const mountWrapper = mount(
+      <TableSearch onSearch={onSearch} onHide={onHide} options={options} initialSearchText="searchText" />,
+    );
+    const actualResult = mountWrapper.find(TextField);
+    assert.strictEqual(actualResult.length, 1);
+    assert.strictEqual(actualResult.props().defaultValue, 'searchText');
+  });
+
   it('should trigger handleTextChange prop callback when calling method handleTextChange', () => {
     const options = { onSearchChange: () => true, textLabels };
     const onSearch = spy();
diff --git a/test/MUIDataTableToolbar.test.js b/test/MUIDataTableToolbar.test.js
index 7e0b7ec..f0ef27f 100644
--- a/test/MUIDataTableToolbar.test.js
+++ b/test/MUIDataTableToolbar.test.js
@@ -70,6 +70,16 @@ describe('<TableToolbar />', function() {
     assert.strictEqual(actualResult.length, 1);
   });
 
+  it('should render a toolbar with search text initialized if option.searchText = some_text', () => {
+    const newOptions = { ...options, search: true, searchText: 'searchText' };
+    const mountWrapper = mount(
+      <TableToolbar columns={columns} data={data} options={newOptions} setTableAction={setTableAction} />,
+    );
+    const actualResult = mountWrapper.find(TableSearch);
+    assert.strictEqual(actualResult.length, 1);
+    assert.strictEqual(actualResult.props().initialSearchText, 'searchText');
+  });
+
   it('should render a toolbar with no search icon if option.search = false', () => {
     const newOptions = { ...options, search: false };
     const mountWrapper = mount(