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 0 | Email 0 | Salary 0 | Job Title 0 | Start Date 0Filter Mode: Less Than | ||
![]() | $52,729 | Chief Creative Technician | 3/20/2014 | ||||
![]() | $71,964 | Forward Response Engineer | 3/9/2018 | ||||
![]() | $72,551 | Customer Intranet Consultant | 8/12/2020 | ||||
![]() | $57,801 | Senior Security Manager | 7/25/2017 | ||||
![]() | $23,792 | Legacy Security Assistant | 4/12/2020 | ||||
![]() | $80,916 | Regional Division Planner | 10/30/2017 | ||||
![]() | $68,052 | Corporate Paradigm Strategist | 1/17/2018 | ||||
![]() | $85,573 | Legacy Functionality Specialist | 8/4/2014 | ||||
![]() | $51,062 | Forward Infrastructure Representative | 1/6/2021 | ||||
![]() | $61,196 | Human Paradigm Designer | 4/28/2016 | ||||
1import React, { useMemo } from 'react';23//MRT Imports4//import MaterialReactTable from 'material-react-table'; //default import deprecated5import { MaterialReactTable } from 'material-react-table';67//Material UI Imports8import { Box, Button, ListItemIcon, MenuItem, Typography } from '@mui/material';910//Date Picker Imports11import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';12import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';13import { DatePicker } from '@mui/x-date-pickers/DatePicker';1415//Icons Imports16import { AccountCircle, Send } from '@mui/icons-material';1718//Mock Data19import { data } from './makeData';2021const Example = () => {22 const columns = useMemo(23 () => [24 {25 id: 'employee', //id used to define `group` column26 header: 'Employee',27 columns: [28 {29 accessorFn: (row) => `${row.firstName} ${row.lastName}`, //accessorFn used to join multiple data into a single cell30 id: 'name', //id is still required when using accessorFn instead of accessorKey31 header: 'Name',32 size: 250,33 Cell: ({ renderedCellValue, row }) => (34 <Box35 sx={{36 display: 'flex',37 alignItems: 'center',38 gap: '1rem',39 }}40 >41 <img42 alt="avatar"43 height={30}44 src={row.original.avatar}45 loading="lazy"46 style={{ borderRadius: '50%' }}47 />48 {/* using renderedCellValue instead of cell.getValue() preserves filter match highlighting */}49 <span>{renderedCellValue}</span>50 </Box>51 ),52 },53 {54 accessorKey: 'email', //accessorKey used to define `data` column. `id` gets set to accessorKey automatically55 enableClickToCopy: true,56 header: 'Email',57 size: 300,58 },59 ],60 },61 {62 id: 'id',63 header: 'Job Info',64 columns: [65 {66 accessorKey: 'salary',67 // filterVariant: 'range', //if not using filter modes feature, use this instead of filterFn68 filterFn: 'between',69 header: 'Salary',70 size: 200,71 //custom conditional format and styling72 Cell: ({ cell }) => (73 <Box74 component="span"75 sx={(theme) => ({76 backgroundColor:77 cell.getValue() < 50_00078 ? theme.palette.error.dark79 : cell.getValue() >= 50_000 && cell.getValue() < 75_00080 ? theme.palette.warning.dark81 : theme.palette.success.dark,82 borderRadius: '0.25rem',83 color: '#fff',84 maxWidth: '9ch',85 p: '0.25rem',86 })}87 >88 {cell.getValue()?.toLocaleString?.('en-US', {89 style: 'currency',90 currency: 'USD',91 minimumFractionDigits: 0,92 maximumFractionDigits: 0,93 })}94 </Box>95 ),96 },97 {98 accessorKey: 'jobTitle', //hey a simple column for once99 header: 'Job Title',100 size: 350,101 },102 {103 accessorFn: (row) => new Date(row.startDate), //convert to Date for sorting and filtering104 id: 'startDate',105 header: 'Start Date',106 filterFn: 'lessThanOrEqualTo',107 sortingFn: 'datetime',108 Cell: ({ cell }) => cell.getValue()?.toLocaleDateString(), //render Date as a string109 Header: ({ column }) => <em>{column.columnDef.header}</em>, //custom header markup110 //Custom Date Picker Filter from @mui/x-date-pickers111 Filter: ({ column }) => (112 <LocalizationProvider dateAdapter={AdapterDayjs}>113 <DatePicker114 onChange={(newValue) => {115 column.setFilterValue(newValue);116 }}117 slotProps={{118 textField: {119 helperText: 'Filter Mode: Less Than',120 sx: { minWidth: '120px' },121 variant: 'standard',122 },123 }}124 value={column.getFilterValue()}125 />126 </LocalizationProvider>127 ),128 },129 ],130 },131 ],132 [],133 );134135 return (136 <MaterialReactTable137 columns={columns}138 data={data}139 enableColumnFilterModes140 enableColumnOrdering141 enableGrouping142 enablePinning143 enableRowActions144 enableRowSelection145 initialState={{ showColumnFilters: true }}146 positionToolbarAlertBanner="bottom"147 renderDetailPanel={({ row }) => (148 <Box149 sx={{150 display: 'flex',151 justifyContent: 'space-around',152 alignItems: 'center',153 }}154 >155 <img156 alt="avatar"157 height={200}158 src={row.original.avatar}159 loading="lazy"160 style={{ borderRadius: '50%' }}161 />162 <Box sx={{ textAlign: 'center' }}>163 <Typography variant="h4">Signature Catch Phrase:</Typography>164 <Typography variant="h1">165 "{row.original.signatureCatchPhrase}"166 </Typography>167 </Box>168 </Box>169 )}170 renderRowActionMenuItems={({ closeMenu }) => [171 <MenuItem172 key={0}173 onClick={() => {174 // View profile logic...175 closeMenu();176 }}177 sx={{ m: 0 }}178 >179 <ListItemIcon>180 <AccountCircle />181 </ListItemIcon>182 View Profile183 </MenuItem>,184 <MenuItem185 key={1}186 onClick={() => {187 // Send email logic...188 closeMenu();189 }}190 sx={{ m: 0 }}191 >192 <ListItemIcon>193 <Send />194 </ListItemIcon>195 Send Email196 </MenuItem>,197 ]}198 renderTopToolbarCustomActions={({ table }) => {199 const handleDeactivate = () => {200 table.getSelectedRowModel().flatRows.map((row) => {201 alert('deactivating ' + row.getValue('name'));202 });203 };204205 const handleActivate = () => {206 table.getSelectedRowModel().flatRows.map((row) => {207 alert('activating ' + row.getValue('name'));208 });209 };210211 const handleContact = () => {212 table.getSelectedRowModel().flatRows.map((row) => {213 alert('contact ' + row.getValue('name'));214 });215 };216217 return (218 <div style={{ display: 'flex', gap: '0.5rem' }}>219 <Button220 color="error"221 disabled={!table.getIsSomeRowsSelected()}222 onClick={handleDeactivate}223 variant="contained"224 >225 Deactivate226 </Button>227 <Button228 color="success"229 disabled={!table.getIsSomeRowsSelected()}230 onClick={handleActivate}231 variant="contained"232 >233 Activate234 </Button>235 <Button236 color="info"237 disabled={!table.getIsSomeRowsSelected()}238 onClick={handleContact}239 variant="contained"240 >241 Contact242 </Button>243 </div>244 );245 }}246 />247 );248};249250export default Example;251
View Extra Storybook Examples