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.
Employee | Job Info | ||||||
---|---|---|---|---|---|---|---|
Actions | Name | Email | Salary | Job Title | Start Date Filter Mode: Less Than | ||
Dusty Kuvalis | $52,729 | Chief Creative Technician | 3/20/2014 | ||||
D'angelo Moen | $71,964 | Forward Response Engineer | 3/9/2018 | ||||
Devan Reinger | $72,551 | Customer Intranet Consultant | 8/12/2020 | ||||
Leonardo Langworth | $57,801 | Senior Security Manager | 7/25/2017 | ||||
Douglas Denesik | $23,792 | Legacy Security Assistant | 4/12/2020 | ||||
Jameson Mayer | $80,916 | Regional Division Planner | 10/30/2017 | ||||
Madaline Quitzon | $68,052 | Corporate Paradigm Strategist | 1/17/2018 | ||||
Wilfrid Vandervort | $85,573 | Legacy Functionality Specialist | 8/4/2014 | ||||
Chelsie Mraz | $51,062 | Forward Infrastructure Representative | 1/6/2021 | ||||
Hassie Bruen | $61,196 | Human Paradigm Designer | 4/28/2016 | ||||
1import React, { useMemo } from 'react';23//MRT Imports4import MaterialReactTable, { MRT_ColumnDef } from 'material-react-table';56//Material-UI Imports7import {8 Box,9 Button,10 ListItemIcon,11 MenuItem,12 Typography,13 TextField,14} from '@mui/material';1516//Date Picker Imports17import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';18import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';19import { DatePicker } from '@mui/x-date-pickers/DatePicker';2021//Icons Imports22import { AccountCircle, Send } from '@mui/icons-material';2324//Mock Data25import { data } from './makeData';2627export type Employee = {28 firstName: string;29 lastName: string;30 email: string;31 jobTitle: string;32 salary: number;33 startDate: string;34 signatureCatchPhrase: string;35 avatar: string;36};3738const Example = () => {39 const columns = useMemo<MRT_ColumnDef<Employee>[]>(40 () => [41 {42 id: 'employee', //id used to define `group` column43 header: 'Employee',44 columns: [45 {46 accessorFn: (row) => `${row.firstName} ${row.lastName}`, //accessorFn used to join multiple data into a single cell47 id: 'name', //id is still required when using accessorFn instead of accessorKey48 header: 'Name',49 size: 250,50 Cell: ({ renderedCellValue, row }) => (51 <Box52 sx={{53 display: 'flex',54 alignItems: 'center',55 gap: '1rem',56 }}57 >58 <img59 alt="avatar"60 height={30}61 src={row.original.avatar}62 loading="lazy"63 style={{ borderRadius: '50%' }}64 />65 {/* using renderedCellValue instead of cell.getValue() preserves filter match highlighting */}66 <span>{renderedCellValue}</span>67 </Box>68 ),69 },70 {71 accessorKey: 'email', //accessorKey used to define `data` column. `id` gets set to accessorKey automatically72 enableClickToCopy: true,73 header: 'Email',74 size: 300,75 },76 ],77 },78 {79 id: 'id',80 header: 'Job Info',81 columns: [82 {83 accessorKey: 'salary',84 filterVariant: 'range',85 header: 'Salary',86 size: 200,87 //custom conditional format and styling88 Cell: ({ cell }) => (89 <Box90 component="span"91 sx={(theme) => ({92 backgroundColor:93 cell.getValue<number>() < 50_00094 ? theme.palette.error.dark95 : cell.getValue<number>() >= 50_000 &&96 cell.getValue<number>() < 75_00097 ? theme.palette.warning.dark98 : theme.palette.success.dark,99 borderRadius: '0.25rem',100 color: '#fff',101 maxWidth: '9ch',102 p: '0.25rem',103 })}104 >105 {cell.getValue<number>()?.toLocaleString?.('en-US', {106 style: 'currency',107 currency: 'USD',108 minimumFractionDigits: 0,109 maximumFractionDigits: 0,110 })}111 </Box>112 ),113 },114 {115 accessorKey: 'jobTitle', //hey a simple column for once116 header: 'Job Title',117 size: 350,118 },119 {120 accessorFn: (row) => new Date(row.startDate), //convert to Date for sorting and filtering121 id: 'startDate',122 header: 'Start Date',123 filterFn: 'lessThanOrEqualTo',124 sortingFn: 'datetime',125 Cell: ({ cell }) => cell.getValue<Date>()?.toLocaleDateString(), //render Date as a string126 Header: ({ column }) => <em>{column.columnDef.header}</em>, //custom header markup127 //Custom Date Picker Filter from @mui/x-date-pickers128 Filter: ({ column }) => (129 <LocalizationProvider dateAdapter={AdapterDayjs}>130 <DatePicker131 onChange={(newValue) => {132 column.setFilterValue(newValue);133 }}134 renderInput={(params) => (135 <TextField136 {...params}137 helperText={'Filter Mode: Less Than'}138 sx={{ minWidth: '120px' }}139 variant="standard"140 />141 )}142 value={column.getFilterValue()}143 />144 </LocalizationProvider>145 ),146 },147 ],148 },149 ],150 [],151 );152153 return (154 <MaterialReactTable155 columns={columns}156 data={data}157 enableColumnFilterModes158 enableColumnOrdering159 enableGrouping160 enablePinning161 enableRowActions162 enableRowSelection163 initialState={{ showColumnFilters: true }}164 positionToolbarAlertBanner="bottom"165 renderDetailPanel={({ row }) => (166 <Box167 sx={{168 display: 'flex',169 justifyContent: 'space-around',170 alignItems: 'center',171 }}172 >173 <img174 alt="avatar"175 height={200}176 src={row.original.avatar}177 loading="lazy"178 style={{ borderRadius: '50%' }}179 />180 <Box sx={{ textAlign: 'center' }}>181 <Typography variant="h4">Signature Catch Phrase:</Typography>182 <Typography variant="h1">183 "{row.original.signatureCatchPhrase}"184 </Typography>185 </Box>186 </Box>187 )}188 renderRowActionMenuItems={({ closeMenu }) => [189 <MenuItem190 key={0}191 onClick={() => {192 // View profile logic...193 closeMenu();194 }}195 sx={{ m: 0 }}196 >197 <ListItemIcon>198 <AccountCircle />199 </ListItemIcon>200 View Profile201 </MenuItem>,202 <MenuItem203 key={1}204 onClick={() => {205 // Send email logic...206 closeMenu();207 }}208 sx={{ m: 0 }}209 >210 <ListItemIcon>211 <Send />212 </ListItemIcon>213 Send Email214 </MenuItem>,215 ]}216 renderTopToolbarCustomActions={({ table }) => {217 const handleDeactivate = () => {218 table.getSelectedRowModel().flatRows.map((row) => {219 alert('deactivating ' + row.getValue('name'));220 });221 };222223 const handleActivate = () => {224 table.getSelectedRowModel().flatRows.map((row) => {225 alert('activating ' + row.getValue('name'));226 });227 };228229 const handleContact = () => {230 table.getSelectedRowModel().flatRows.map((row) => {231 alert('contact ' + row.getValue('name'));232 });233 };234235 return (236 <div style={{ display: 'flex', gap: '0.5rem' }}>237 <Button238 color="error"239 disabled={!table.getIsSomeRowsSelected()}240 onClick={handleDeactivate}241 variant="contained"242 >243 Deactivate244 </Button>245 <Button246 color="success"247 disabled={!table.getIsSomeRowsSelected()}248 onClick={handleActivate}249 variant="contained"250 >251 Activate252 </Button>253 <Button254 color="info"255 disabled={!table.getIsSomeRowsSelected()}256 onClick={handleContact}257 variant="contained"258 >259 Contact260 </Button>261 </div>262 );263 }}264 />265 );266};267268export default Example;269
View Extra Storybook Examples