mui-datatables is a powerful, feature-rich data table component for React built on Material-UI that provides comprehensive functionality including sorting, filtering, pagination, search, export, and custom rendering. It offers extensive customization options and advanced features for building complex data management interfaces. This guide walks through implementing advanced table features using mui-datatables with React, covering custom components, server-side processing, and enterprise-grade implementations. This is part 12 of a series on using mui-datatables with React.
Prerequisites
Before you begin, ensure you have:
- Node.js version 16.0 or higher
- npm, yarn, or pnpm package manager
- A React project (version 16.8 or higher) with hooks support
- Advanced understanding of React hooks, context API, and state management
- Material-UI installed (required dependency)
- Familiarity with TypeScript (recommended)
- Knowledge of async operations and API integration
Installation
First, install Material-UI core components (required dependency):
npm install @mui/material @mui/icons-material @emotion/react @emotion/styled
Then install mui-datatables:
npm install mui-datatables
Or install everything with yarn:
yarn add @mui/material @mui/icons-material @emotion/react @emotion/styled mui-datatables
Or with pnpm:
pnpm add @mui/material @mui/icons-material @emotion/react @emotion/styled mui-datatables
Your package.json should include:
{
"dependencies": {
"mui-datatables": "^4.0.0",
"@mui/material": "^5.0.0",
"@mui/icons-material": "^5.0.0",
"@emotion/react": "^11.0.0",
"@emotion/styled": "^11.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
Project Setup
mui-datatables requires Material-UI's theme provider. Set up your app with the Material-UI theme:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import App from './App';
const theme = createTheme();
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<ThemeProvider theme={theme}>
<CssBaseline />
<App />
</ThemeProvider>
</React.StrictMode>
);
First Example / Basic Usage
Let's create a basic table component. Create src/DataTable.jsx:
// src/DataTable.jsx
import React from 'react';
import MUIDataTable from 'mui-datatables';
function DataTable() {
const columns = [
{ name: 'id', label: 'ID', options: { filter: false } },
{ name: 'name', label: 'Name' },
{ name: 'email', label: 'Email' },
{ name: 'age', label: 'Age', options: { filter: false } },
{ name: 'city', label: 'City' }
];
const data = [
{ id: 1, name: 'John Doe', email: 'john@example.com', age: 28, city: 'New York' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', age: 32, city: 'London' },
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', age: 45, city: 'Paris' },
{ id: 4, name: 'Alice Williams', email: 'alice@example.com', age: 29, city: 'Tokyo' }
];
const options = {
filterType: 'checkbox',
responsive: 'standard',
selectableRows: 'multiple',
print: false,
download: true,
search: true,
pagination: true
};
return (
<div style={{ padding: '20px' }}>
<MUIDataTable
title="Employee Directory"
data={data}
columns={columns}
options={options}
/>
</div>
);
}
export default DataTable;
Understanding the Basics
mui-datatables uses a column-based configuration where:
- name: Property key in your data objects
- label: Column header text
- options: Column-specific options (filtering, sorting, custom rendering)
Key concepts for advanced usage:
-
Custom Renderers: Use
customBodyRenderfor custom cell content - Custom Filters: Implement custom filter components
- Server-side Processing: Load data asynchronously from APIs
- Options: Extensive configuration options for table behavior
- Events: Handle row selection, cell clicks, and other interactions
Here's an example with custom rendering and filters:
// src/AdvancedTable.jsx
import React, { useState } from 'react';
import MUIDataTable from 'mui-datatables';
import { Chip, IconButton } from '@mui/material';
import EditIcon from '@mui/icons-material/Edit';
import DeleteIcon from '@mui/icons-material/Delete';
function AdvancedTable() {
const [data, setData] = useState([
{ id: 1, name: 'Laptop', category: 'Electronics', price: 999.99, stock: 15, status: 'In Stock' },
{ id: 2, name: 'Mouse', category: 'Electronics', price: 29.99, stock: 8, status: 'Low Stock' },
{ id: 3, name: 'Keyboard', category: 'Electronics', price: 79.99, stock: 12, status: 'In Stock' }
]);
const columns = [
{
name: 'id',
label: 'ID',
options: { filter: false, sort: true }
},
{
name: 'name',
label: 'Product Name'
},
{
name: 'category',
label: 'Category',
options: {
filter: true,
filterType: 'dropdown'
}
},
{
name: 'price',
label: 'Price',
options: {
customBodyRender: (value) => `$${value.toFixed(2)}`,
filter: false
}
},
{
name: 'stock',
label: 'Stock',
options: {
customBodyRender: (value) => (
<span style={{
color: value < 10 ? 'red' : 'green',
fontWeight: 'bold'
}}>
{value}
</span>
),
filter: false
}
},
{
name: 'status',
label: 'Status',
options: {
customBodyRender: (value) => (
<Chip
label={value}
color={value === 'In Stock' ? 'success' : 'warning'}
size="small"
/>
),
filter: true,
filterType: 'dropdown'
}
},
{
name: 'actions',
label: 'Actions',
options: {
filter: false,
sort: false,
customBodyRender: (value, tableMeta) => {
const rowIndex = tableMeta.rowIndex;
return (
<>
<IconButton
size="small"
onClick={() => handleEdit(rowIndex)}
color="primary"
>
<EditIcon />
</IconButton>
<IconButton
size="small"
onClick={() => handleDelete(rowIndex)}
color="error"
>
<DeleteIcon />
</IconButton>
</>
);
}
}
}
];
const handleEdit = (rowIndex) => {
console.log('Edit row:', data[rowIndex]);
// Implement edit logic
};
const handleDelete = (rowIndex) => {
const newData = data.filter((_, index) => index !== rowIndex);
setData(newData);
};
const options = {
filterType: 'multiselect',
responsive: 'standard',
selectableRows: 'multiple',
selectableRowsOnClick: true,
rowsPerPage: 10,
rowsPerPageOptions: [5, 10, 20, 50],
onRowsDelete: (rowsDeleted) => {
const indices = rowsDeleted.data.map(d => d.dataIndex);
setData(data.filter((_, index) => !indices.includes(index)));
return false; // Prevent default deletion
},
customToolbar: () => {
return (
<button
onClick={() => console.log('Custom action')}
style={{ marginRight: '10px', padding: '8px 16px' }}
>
Custom Action
</button>
);
}
};
return (
<div style={{ padding: '20px' }}>
<MUIDataTable
title="Product Inventory"
data={data}
columns={columns}
options={options}
/>
</div>
);
}
export default AdvancedTable;
Practical Example / Building Something Real
Let's build a comprehensive admin dashboard with server-side processing:
// src/AdminDashboard.jsx
import React, { useState, useEffect, useCallback } from 'react';
import MUIDataTable from 'mui-datatables';
import { Chip, IconButton, Button, Box } from '@mui/material';
import EditIcon from '@mui/icons-material/Edit';
import DeleteIcon from '@mui/icons-material/Delete';
import AddIcon from '@mui/icons-material/Add';
function AdminDashboard() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [totalCount, setTotalCount] = useState(0);
const fetchData = useCallback(async (page, pageSize, searchText, sortOrder) => {
setLoading(true);
try {
// Simulate API call
const params = new URLSearchParams({
page: page.toString(),
limit: pageSize.toString(),
search: searchText || '',
sortBy: sortOrder?.name || '',
sortOrder: sortOrder?.direction || 'asc'
});
const response = await fetch(`/api/users?${params}`);
const result = await response.json();
setData(result.data);
setTotalCount(result.total);
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
fetchData(0, 10, '', null);
}, [fetchData]);
const columns = [
{
name: 'id',
label: 'ID',
options: {
filter: false,
sort: true,
display: true
}
},
{
name: 'avatar',
label: 'Avatar',
options: {
filter: false,
sort: false,
customBodyRender: (value) => (
<img
src={value || '/default-avatar.png'}
alt="Avatar"
style={{
width: '40px',
height: '40px',
borderRadius: '50%',
objectFit: 'cover'
}}
/>
)
}
},
{
name: 'name',
label: 'Full Name',
options: {
filter: true,
customBodyRender: (value, tableMeta) => {
const row = data[tableMeta.rowIndex];
return (
<div>
<strong>{value}</strong>
<div style={{ fontSize: '12px', color: '#666' }}>
{row.email}
</div>
</div>
);
}
}
},
{
name: 'department',
label: 'Department',
options: {
filter: true,
filterType: 'multiselect',
customBodyRender: (value) => {
const colors = {
Engineering: '#dc3545',
Marketing: '#ffc107',
Sales: '#28a745',
HR: '#17a2b8'
};
return (
<Chip
label={value}
size="small"
style={{
backgroundColor: colors[value] || '#6c757d',
color: 'white'
}}
/>
);
}
}
},
{
name: 'salary',
label: 'Salary',
options: {
filter: false,
sort: true,
customBodyRender: (value) => `$${value.toLocaleString()}`,
customSort: (data1, data2) => {
return data1[4] - data2[4];
}
}
},
{
name: 'status',
label: 'Status',
options: {
filter: true,
filterType: 'dropdown',
customBodyRender: (value) => (
<Chip
label={value}
color={value === 'Active' ? 'success' : 'error'}
size="small"
/>
)
}
},
{
name: 'lastLogin',
label: 'Last Login',
options: {
filter: false,
customBodyRender: (value) => {
if (!value) return 'Never';
const date = new Date(value);
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric'
});
}
}
},
{
name: 'actions',
label: 'Actions',
options: {
filter: false,
sort: false,
customBodyRender: (value, tableMeta) => {
const rowIndex = tableMeta.rowIndex;
return (
<>
<IconButton
size="small"
onClick={() => handleEdit(rowIndex)}
color="primary"
>
<EditIcon />
</IconButton>
<IconButton
size="small"
onClick={() => handleDelete(rowIndex)}
color="error"
>
<DeleteIcon />
</IconButton>
</>
);
}
}
}
];
const handleEdit = (rowIndex) => {
console.log('Edit user:', data[rowIndex]);
// Implement edit logic
};
const handleDelete = async (rowIndex) => {
if (window.confirm('Are you sure you want to delete this user?')) {
try {
await fetch(`/api/users/${data[rowIndex].id}`, { method: 'DELETE' });
fetchData(0, 10, '', null);
} catch (error) {
console.error('Delete failed:', error);
}
}
};
const options = {
serverSide: true,
count: totalCount,
page: 0,
rowsPerPage: 10,
rowsPerPageOptions: [5, 10, 20, 50],
filterType: 'multiselect',
responsive: 'standard',
selectableRows: 'multiple',
search: true,
download: true,
print: false,
onTableChange: (action, tableState) => {
switch (action) {
case 'changePage':
fetchData(tableState.page, tableState.rowsPerPage, tableState.searchText, tableState.sortOrder);
break;
case 'changeRowsPerPage':
fetchData(0, tableState.rowsPerPage, tableState.searchText, tableState.sortOrder);
break;
case 'search':
fetchData(tableState.page, tableState.rowsPerPage, tableState.searchText, tableState.sortOrder);
break;
case 'sort':
fetchData(tableState.page, tableState.rowsPerPage, tableState.searchText, tableState.sortOrder);
break;
case 'filterChange':
fetchData(tableState.page, tableState.rowsPerPage, tableState.searchText, tableState.sortOrder);
break;
default:
break;
}
},
customToolbar: () => {
return (
<Button
variant="contained"
color="primary"
startIcon={<AddIcon />}
onClick={() => console.log('Add new user')}
style={{ marginRight: '10px' }}
>
Add User
</Button>
);
},
onRowsDelete: (rowsDeleted) => {
const indices = rowsDeleted.data.map(d => d.dataIndex);
const idsToDelete = indices.map(i => data[i].id);
// Delete multiple rows
Promise.all(
idsToDelete.map(id =>
fetch(`/api/users/${id}`, { method: 'DELETE' })
)
).then(() => {
fetchData(0, 10, '', null);
});
return false;
}
};
return (
<Box sx={{ p: 3 }}>
<MUIDataTable
title="Admin Dashboard"
data={data}
columns={columns}
options={options}
/>
</Box>
);
}
export default AdminDashboard;
This advanced example demonstrates:
- Server-side data loading with pagination, sorting, and filtering
- Custom cell rendering with React components (Chip, IconButton, images)
- Custom filters with multiselect and dropdown options
- Row selection and bulk deletion
- Custom toolbar with action buttons
- Real-time data updates
- Loading states
- Custom sorting logic
- Event handling for all table interactions
Common Issues / Troubleshooting
Table not rendering: Ensure you've wrapped your app with Material-UI's
ThemeProviderand imported the necessary CSS. Verify that your data array and columns array are properly structured.Server-side processing not working: Make sure you've set
serverSide: truein options and implemented theonTableChangehandler to fetch data based on table state changes.Custom rendering not working: Verify that you're using
customBodyRendercorrectly in column options. The function receives(value, tableMeta)parameters.Filtering issues: Ensure you've set appropriate
filterTypein column options ('checkbox', 'dropdown', 'multiselect', etc.). Some filter types require specific data formats.Performance issues: For large datasets, always use server-side processing. Client-side processing can be slow with thousands of rows.
TypeScript errors: Install type definitions if available. mui-datatables has TypeScript support, so ensure your column and data types match the expected interfaces.
Next Steps
Now that you've mastered mui-datatables:
- Explore advanced customization options and themes
- Implement custom filter components
- Add export functionality (CSV, Excel, PDF)
- Learn about column resizing and reordering
- Implement row expansion for nested data
- Add custom footer and header components
- Check the official repository: https://github.com/gregnb/mui-datatables
- Look for part 13 of this series for more advanced topics
Summary
You've learned how to implement advanced data table features with mui-datatables, including server-side processing, custom rendering, filtering, sorting, and complex interactions. The library provides extensive functionality for building enterprise-grade data management interfaces with Material-UI's design system and excellent performance.
SEO Keywords
mui-datatables React
mui-datatables tutorial
React advanced data table
mui-datatables installation
React Material-UI table
mui-datatables server-side
React data grid advanced
mui-datatables custom rendering
React table component
mui-datatables setup
React interactive table
mui-datatables filtering
React enterprise table
mui-datatables pagination
React Material-UI data table
Top comments (0)