So the desktop query for datagrid looks good, however I think it needs a mobile media query (exactly like this: https://css-tricks.com/responsive-data-tables/) I am dealing with data from an api so I can't do what theyre doing with the text on the css.
I've been searching the mui docs for 4 days with no luck. Does anybody have any ideas as to how to do this with DataGrid?
Here's what I've done. I've made a Table component that looks at the media query and renders Desktop or Mobile table component depending on the media query:
import useTheme from '@mui/system/useTheme';
import useMediaQuery from '@mui/material/useMediaQuery';
import TableMobile from './TableMobile';
import TableDesktop from './TableDesktop';
function Table(props) {
const theme = useTheme();
const isSmScreen = useMediaQuery(theme.breakpoints.down('sm'));
return isSmScreen ? <TableMobile {...props} /> : <TableDesktop {...props} />;
}
export default Table;
Nothing special on the table desktop, it is just a regular MUI table that takes and displays the data.
Below is the mobile table component, the trick is with the tableCellStyles, it takes a data attribute to display the column header. I basically ditched TableHead and went with a Rows approach.
import { useMemo } from 'react';
import {
useTable,
usePagination,
useFilters,
useGlobalFilter,
useExpanded,
} from 'react-table';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableRow from '@mui/material/TableRow';
import TableFooter from '@mui/material/TableFooter';
import Paper from '@mui/material/Paper';
import TablePagination from '@mui/material/TablePagination';
import MobileTableNavigation from './MobileTableNavigation';
const tableCellStyles = {
display: 'block',
'&::before': {
content: 'attr(data-label)',
float: 'left',
fontWeight: 700,
},
fontSize: '12px',
color: '#fff',
};
export default function TableMobile({
data,
columns,
rowsPerPageOptionsMobile = [3, 5, 10, 15, 20, 25, 30],
initialStateMobile = {
pageIndex: 0,
pageSize: 3,
},
autoResetPage = true,
}) {
// react-table requires a default column when using filters.
const defaultColumn = useMemo(
() => ({
Filter: <></>,
}),
[]
);
const {
gotoPage,
setPageSize,
pageOptions,
state: { pageIndex, pageSize },
getTableProps,
getTableBodyProps,
page: rows, // Instead of using 'rows', we'll use page,
// which has only the rows for the active page
prepareRow,
} = useTable(
{
defaultColumn,
columns,
autoResetPage,
data,
initialState: initialStateMobile,
},
useFilters,
useGlobalFilter,
useExpanded,
usePagination
); // react-table hooks
return (
<>
<Paper sx={{ width: '100%' }}>
<TableContainer>
<Table {...getTableProps()}>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={rowsPerPageOptionsMobile}
component="div"
sx={{
'& .MuiToolbar-root': {
width: '100%',
gap: '10px',
},
'& .MuiTablePagination-displayedRows': {
order: 0,
flex: 1,
position: 'absolute',
left: '22px',
color: '#fff',
},
'& .MuiTablePagination-selectLabel': {
color: '#fff',
},
'& .MuiInputBase-root': {
'.MuiTablePagination-select': {
display: 'flex',
width: '30px',
border: '1px solid',
borderColor: 'primary.linkColor',
borderRadius: '5px',
color: 'primary.linkColor',
},
'.MuiTablePagination-selectIcon': {
color: 'primary.linkColor',
},
},
}}
count={rows.length}
rowsPerPage={pageSize}
page={pageIndex}
onPageChange={gotoPage}
onRowsPerPageChange={(e) =>
setPageSize(Number(e.target.value))
}
labelRowsPerPage="Results per page:"
labelDisplayedRows={() =>
`${pageIndex + 1}-${pageOptions?.length} of ${
pageOptions?.length
}`
}
ActionsComponent={() => <></>}
/>
</TableRow>
</TableFooter>
</Table>
<Table
sx={{
borderCollapse: 'collapse',
margin: 0,
padding: 0,
width: '100%',
tableLayout: 'fixed',
}}
size="small">
<TableBody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<>
<TableRow
{...row.getRowProps()}
key={row?.id}
sx={{
display: 'block',
padding: '0.35em',
borderBottom: '27px solid #F1F1F1',
boxShadow: 'inset 0 -7px 10px -11px',
}}>
{/* dont include the id field */}
{row.cells.map((cell, idx) => {
return (
<TableCell
key={idx}
data-label={cell.column.Header || 'ERR::NO_HEADER'}
align="right"
sx={tableCellStyles}
{...cell.getCellProps()}>
{cell.render('Cell')}
</TableCell>
);
})}
</TableRow>
</>
);
})}
</TableBody>
</Table>
</TableContainer>
</Paper>
<MobileTableNavigation
currentPage={pageIndex}
onPageChange={gotoPage}
rowsPerPage={pageSize}
totalRowsCount={data.length}
/>
</>
);
}
and just in case. Here is the desktop table component for you, so you can see the difference in the order of the components and the style choices.
import { useMemo } from 'react';
import {
useTable,
usePagination,
useFilters,
useGlobalFilter,
useExpanded,
} from 'react-table';
import { makeStyles } from '@mui/styles';
// components
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import TableFooter from '@mui/material/TableFooter';
import TablePagination from '@mui/material/TablePagination';
import IconButton from '@mui/material/IconButton';
import Grid from '@mui/material/Grid';
import Paper from '@mui/material/Paper';
// icons
import FirstPageIcon from '@mui/icons-material/FirstPage';
import LastPageIcon from '@mui/icons-material/LastPage';
import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft';
import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight';
const useStyles = makeStyles((theme) => ({
tableRoot: {
width: '100%',
maxWidth: '1100px',
},
tableContainer: {
maxHeight: 500,
},
tableBody: {
background: theme.palette.background.paper,
},
pagination: {
background: theme.palette.background.paper,
},
paginationSpacer: {
flex: '1 1 100%',
[theme.breakpoints.down('md')]: {
flex: '0 0',
},
},
paginationActions: {
flexShrink: 0,
marginLeft: theme.spacing(2.5),
[theme.breakpoints.down('sm')]: {
flexShrink: 1, // direction buttons in a column in small screen
},
},
tableHeader: { maxWidth: '200px', width: '250px' },
tableHead: {
background: theme.palette.background.paper,
},
}));
export default function TableDesktop({
columns,
data,
autoResetPage = true,
initialStateDesktop = {
pageIndex: 0,
pageSize: 10,
// filters: [{ id: 'isActive', value: true }],
},
filterColumnProps,
rowsPerPageOptionsDesktop = [10, 20, 30, 40, 50, 100],
}) {
// react-table requires a default column when using filters.
const defaultColumn = useMemo(
() => ({
Filter: <></>,
}),
[]
);
const {
gotoPage,
setPageSize,
pageOptions,
state: { pageIndex, pageSize },
getTableProps,
getTableBodyProps,
headerGroups,
page: rows, // Instead of using 'rows', we'll use page,
// which has only the rows for the active page
prepareRow,
} = useTable(
{
defaultColumn,
columns,
autoResetPage,
data,
initialState: initialStateDesktop,
},
useFilters,
useGlobalFilter,
useExpanded,
usePagination
); // react-table hooks
const classes = useStyles();
return (
<Paper sx={{ width: '100%' }}>
<TableContainer className={classes.tableContainer}>
<Table stickyHeader className={classes.table} {...getTableProps()}>
<TableHead className={classes.tableHead}>
{/* COLUMN HEADERS */}
{headerGroups.map((headerGroup) => (
<TableRow {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column, key) => {
return (
<TableCell
key={key}
{...column.getHeaderProps()}
className={classes.tableHeader}>
<Grid container direction="column">
<Grid item>{column.render('Header')}</Grid>
<Grid item>
{column.canFilter
? column.render('Filter', filterColumnProps) // pass props to column
: null}
</Grid>
</Grid>
</TableCell>
);
})}
</TableRow>
))}
</TableHead>
<TableBody {...getTableBodyProps()} className={classes.tableBody}>
{rows.map((row, idx) => {
prepareRow(row);
// table rows
return (
<TableRow tabIndex={-1} {...row.getRowProps()} hover key={idx}>
{row.cells.map((cell, idx) => {
return (
// cell of row.
<TableCell
key={idx}
style={{ maxWidth: '200px' }}
{...cell.getCellProps()}>
{cell.render('Cell')}
</TableCell>
);
})}
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
<Table>
<TableFooter>
<TableRow>
{/* TABLE PAGINATION */}
{/* Material UI TablePagination component */}
<TablePagination
rowsPerPageOptions={rowsPerPageOptionsDesktop}
colSpan={0}
className={classes.pagination}
count={pageOptions.length}
rowsPerPage={pageSize}
onPageChange={gotoPage}
page={pageIndex}
labelRowsPerPage="Results per page:"
classes={{ spacer: classes.paginationSpacer }}
onRowsPerPageChange={(e) => setPageSize(Number(e.target.value))}
labelDisplayedRows={() =>
`${pageIndex + 1}-${pageOptions?.length} of ${
pageOptions?.length
}`
}
ActionsComponent={(props) => {
const { page, onPageChange } = props;
const canGoNext = page < pageOptions?.length - 1;
const canGoBack = page > 0;
const handleFirstPageButtonClick = () => {
onPageChange(0);
};
const handleBackButtonClick = () => {
// if (!canPreviousPage) return;
if (!canGoBack) return;
const previousPage = page - 1;
onPageChange(previousPage);
};
const handleNextButtonClick = () => {
// if (!canNextPage) return;
if (!canGoNext) return;
const nextPage = page + 1;
onPageChange(nextPage);
};
const handleLastPageButtonClick = () => {
// onPageChange(Math.max(0, Math.ceil(count / rowsPerPage) - 1));
onPageChange(pageOptions?.length - 1);
};
return (
<div className={classes.paginationActions}>
<IconButton
onClick={handleFirstPageButtonClick}
disabled={page === 0}
aria-label="first page">
<FirstPageIcon />
</IconButton>
<IconButton
onClick={handleBackButtonClick}
disabled={page === 0}
aria-label="previous page">
<KeyboardArrowLeft />
</IconButton>
<IconButton
onClick={handleNextButtonClick}
// disabled={page >= Math.ceil(count / rowsPerPage) - 1}
disabled={!canGoNext}
aria-label="next page">
<KeyboardArrowRight />
</IconButton>
<IconButton
onClick={handleLastPageButtonClick}
// disabled={page >= Math.ceil(count / rowsPerPage) - 1}
disabled={!canGoNext}
aria-label="last page">
<LastPageIcon />
</IconButton>
</div>
);
}}
/>
</TableRow>
</TableFooter>
</Table>
</Paper>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With