MRT logoMaterial React Table

Advanced Example

Here is a more advanced example showcasing Material React Table's many features. Features such as row selection, expanding detail panels, header groups, column ordering, column pinning, column grouping, custom column and cell renders, etc., can be seen here.

This example is still only using client-side features. If you want to see an example of how to use Material React Table with server side logic and remote data, check out either the Remote Data Example or the React-Query Example.


Filter Mode: Lesss Than

avatar

Dusty Kuvalis

$52,729
Chief Creative Technician3/20/2014
avatar

D'angelo Moen

$71,964
Forward Response Engineer3/9/2018
avatar

Devan Reinger

$72,551
Customer Intranet Consultant8/12/2020
avatar

Leonardo Langworth

$57,801
Senior Security Manager7/25/2017
avatar

Douglas Denesik

$23,792
Legacy Security Assistant4/12/2020
avatar

Jameson Mayer

$80,916
Regional Division Planner10/30/2017
avatar

Madaline Quitzon

$68,052
Corporate Paradigm Strategist1/17/2018
avatar

Wilfrid Vandervort

$85,573
Legacy Functionality Specialist8/4/2014
avatar

Chelsie Mraz

$51,062
Forward Infrastructure Representative1/6/2021
avatar

Hassie Bruen

$61,196
Human Paradigm Designer4/28/2016

Rows per page

1-10 of 128

Source Code

1import React, { useMemo } from 'react';
2
3//MRT Imports
4import MaterialReactTable from 'material-react-table';
5
6//Material-UI Imports
7import {
8 Box,
9 Button,
10 ListItemIcon,
11 MenuItem,
12 Typography,
13 TextField,
14} from '@mui/material';
15
16//Date Picker Imports
17import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
18import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
19import { DatePicker } from '@mui/x-date-pickers/DatePicker';
20
21//Icons Imports
22import { AccountCircle, Send } from '@mui/icons-material';
23
24//Mock Data
25import { data } from './makeData';
26
27const Example = () => {
28 const columns = useMemo(
29 () => [
30 {
31 id: 'employee', //id used to define `group` column
32 header: 'Employee',
33 columns: [
34 {
35 accessorFn: (row) => `${row.firstName} ${row.lastName}`, //accessorFn used to join multiple data into a single cell
36 id: 'name', //id is still required when using accessorFn instead of accessorKey
37 header: 'Name',
38 size: 250,
39 Cell: ({ cell, row }) => (
40 <Box
41 sx={{
42 display: 'flex',
43 alignItems: 'center',
44 gap: '1rem',
45 }}
46 >
47 <img
48 alt="avatar"
49 height={30}
50 src={row.original.avatar}
51 loading="lazy"
52 style={{ borderRadius: '50%' }}
53 />
54 <Typography>{cell.getValue()}</Typography>
55 </Box>
56 ),
57 },
58 {
59 accessorKey: 'email', //accessorKey used to define `data` column. `id` gets set to accessorKey automatically
60 enableClickToCopy: true,
61 header: 'Email',
62 size: 300,
63 },
64 ],
65 },
66 {
67 id: 'id',
68 header: 'Job Info',
69 columns: [
70 {
71 accessorKey: 'salary',
72 filterVariant: 'range',
73 header: 'Salary',
74 size: 200,
75 //custom conditional format and styling
76 Cell: ({ cell }) => (
77 <Box
78 sx={(theme) => ({
79 backgroundColor:
80 cell.getValue() < 50_000
81 ? theme.palette.error.dark
82 : cell.getValue() >= 50_000 && cell.getValue() < 75_000
83 ? theme.palette.warning.dark
84 : theme.palette.success.dark,
85 borderRadius: '0.25rem',
86 color: '#fff',
87 maxWidth: '9ch',
88 p: '0.25rem',
89 })}
90 >
91 {cell.getValue()?.toLocaleString?.('en-US', {
92 style: 'currency',
93 currency: 'USD',
94 minimumFractionDigits: 0,
95 maximumFractionDigits: 0,
96 })}
97 </Box>
98 ),
99 },
100 {
101 accessorKey: 'jobTitle', //hey a simple column for once
102 header: 'Job Title',
103 size: 350,
104 },
105 {
106 accessorFn: (row) => new Date(row.startDate), //convert to Date for sorting and filtering
107 id: 'startDate',
108 header: 'Start Date',
109 filterFn: 'lessThanOrEqualTo',
110 sortingFn: 'datetime',
111 Cell: ({ cell }) => cell.getValue()?.toLocaleDateString(), //render Date as a string
112 Header: ({ column }) => <em>{column.columnDef.header}</em>, //custom header markup
113 //Custom Date Picker Filter from @mui/x-date-pickers
114 Filter: ({ column }) => (
115 <LocalizationProvider dateAdapter={AdapterDayjs}>
116 <DatePicker
117 onChange={(newValue) => {
118 column.setFilterValue(newValue);
119 }}
120 renderInput={(params) => (
121 <TextField
122 {...params}
123 helperText={'Filter Mode: Lesss Than'}
124 sx={{ minWidth: '120px' }}
125 variant="standard"
126 />
127 )}
128 value={column.getFilterValue()}
129 />
130 </LocalizationProvider>
131 ),
132 },
133 ],
134 },
135 ],
136 [],
137 );
138
139 return (
140 <MaterialReactTable
141 columns={columns}
142 data={data}
143 enableColumnFilterModes
144 enableColumnOrdering
145 enableGrouping
146 enablePinning
147 enableRowActions
148 enableRowSelection
149 initialState={{ showColumnFilters: true }}
150 positionToolbarAlertBanner="bottom"
151 renderDetailPanel={({ row }) => (
152 <Box
153 sx={{
154 display: 'flex',
155 justifyContent: 'space-around',
156 alignItems: 'center',
157 }}
158 >
159 <img
160 alt="avatar"
161 height={200}
162 src={row.original.avatar}
163 loading="lazy"
164 style={{ borderRadius: '50%' }}
165 />
166 <Box sx={{ textAlign: 'center' }}>
167 <Typography variant="h4">Signature Catch Phrase:</Typography>
168 <Typography variant="h1">
169 &quot;{row.original.signatureCatchPhrase}&quot;
170 </Typography>
171 </Box>
172 </Box>
173 )}
174 renderRowActionMenuItems={({ closeMenu }) => [
175 <MenuItem
176 key={0}
177 onClick={() => {
178 // View profile logic...
179 closeMenu();
180 }}
181 sx={{ m: 0 }}
182 >
183 <ListItemIcon>
184 <AccountCircle />
185 </ListItemIcon>
186 View Profile
187 </MenuItem>,
188 <MenuItem
189 key={1}
190 onClick={() => {
191 // Send email logic...
192 closeMenu();
193 }}
194 sx={{ m: 0 }}
195 >
196 <ListItemIcon>
197 <Send />
198 </ListItemIcon>
199 Send Email
200 </MenuItem>,
201 ]}
202 renderTopToolbarCustomActions={({ table }) => {
203 const handleDeactivate = () => {
204 table.getSelectedRowModel().flatRows.map((row) => {
205 alert('deactivating ' + row.getValue('name'));
206 });
207 };
208
209 const handleActivate = () => {
210 table.getSelectedRowModel().flatRows.map((row) => {
211 alert('activating ' + row.getValue('name'));
212 });
213 };
214
215 const handleContact = () => {
216 table.getSelectedRowModel().flatRows.map((row) => {
217 alert('contact ' + row.getValue('name'));
218 });
219 };
220
221 return (
222 <div style={{ display: 'flex', gap: '0.5rem' }}>
223 <Button
224 color="error"
225 disabled={table.getSelectedRowModel().flatRows.length === 0}
226 onClick={handleDeactivate}
227 variant="contained"
228 >
229 Deactivate
230 </Button>
231 <Button
232 color="success"
233 disabled={table.getSelectedRowModel().flatRows.length === 0}
234 onClick={handleActivate}
235 variant="contained"
236 >
237 Activate
238 </Button>
239 <Button
240 color="info"
241 disabled={table.getSelectedRowModel().flatRows.length === 0}
242 onClick={handleContact}
243 variant="contained"
244 >
245 Contact
246 </Button>
247 </div>
248 );
249 }}
250 />
251 );
252};
253
254export default Example;
255

View Extra Storybook Examples