I have a Material UI (MUI) table with a border color and background color. Each table row needs to have a collapsible table row. MUI's documentation shows a separate table row and uses React.Fragment, but I want to nest the collapsible table row inside the main table row. This way, the border color and background color remain consistent across all rows, even when collapsed.
Currently, since the rows are separate, the background and border color only apply to the first table row. I tried putting the collapsible table row inside the first table row, but the UI looks weird. I also tried conditionally removing the border bottom from the first table row and the border top from the collapsible table row if the state is open, but it doesn't achieve the desired result due to some space remaining. I'm looking for a better solution that maintains consistent border and background colors across all table rows with collapsible rows.
I've included the code and a CodeSandbox link for reference. Thank you in advance for your help! https://codesandbox.io/p/sandbox/epic-breeze-xvzykk
import * as React from "react";
import PropTypes from "prop-types";
import Box from "@mui/material/Box";
import Collapse from "@mui/material/Collapse";
import IconButton from "@mui/material/IconButton";
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 Typography from "@mui/material/Typography";
import Paper from "@mui/material/Paper";
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
function createData(name, calories, fat, carbs, protein, price) {
return {
name,
calories,
fat,
carbs,
protein,
price,
history: [
{
date: "2020-01-05",
customerId: "11091700",
amount: 3,
},
{
date: "2020-01-02",
customerId: "Anonymous",
amount: 1,
},
],
};
}
function Row(props) {
const { row } = props;
const [open, setOpen] = React.useState(false);
return (
<React.Fragment>
<TableRow
// sx={{ "& > *": { borderBottom: "unset" } }}
sx={{
position: "relative",
zIndex: 0,
backgroundClip: "padding-box",
borderRadius: "10px",
"&:after": {
border: "1px solid transparent",
position: "absolute",
top: 1,
left: 1,
right: 1,
bottom: 1,
background:
"linear-gradient(#161753 0 0) padding-box,linear-gradient(to right, #4b4e8b, #4b4e8b) border-box",
content: '""',
zIndex: -1,
borderRadius: "10px",
},
}}
>
<TableCell sx={{ color: "yellow" }}>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
sx={{ color: "white" }}
>
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
<TableCell sx={{ color: "yellow" }} component="th" scope="row">
{row.name}
</TableCell>
<TableCell sx={{ color: "yellow" }} align="right">
{row.calories}
</TableCell>
<TableCell sx={{ color: "yellow" }} align="right">
{row.fat}
</TableCell>
<TableCell sx={{ color: "yellow" }} align="right">
{row.carbs}
</TableCell>
<TableCell sx={{ color: "yellow" }} align="right">
{row.protein}
</TableCell>
</TableRow>
<TableRow>
<TableCell
sx={{ color: "black" }}
style={{ paddingBottom: 0, paddingTop: 0 }}
colSpan={6}
>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box sx={{ margin: 1 }}>
<Typography variant="h6" gutterBottom component="div">
History
</Typography>
<Table size="small" aria-label="purchases">
<TableHead>
<TableRow>
<TableCell sx={{ color: "black" }}>Date</TableCell>
<TableCell sx={{ color: "black" }}>Customer</TableCell>
<TableCell sx={{ color: "black" }} align="right">
Amount
</TableCell>
<TableCell sx={{ color: "black" }} align="right">
Total price ($)
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{row.history.map((historyRow) => (
<TableRow key={historyRow.date}>
<TableCell
sx={{ color: "black" }}
component="th"
scope="row"
>
{historyRow.date}
</TableCell>
<TableCell sx={{ color: "black" }}>
{historyRow.customerId}
</TableCell>
<TableCell sx={{ color: "black" }} align="right">
{historyRow.amount}
</TableCell>
<TableCell sx={{ color: "black" }} align="right">
{Math.round(historyRow.amount * row.price * 100) / 100}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Box>
</Collapse>
</TableCell>
</TableRow>
</React.Fragment>
);
}
Row.propTypes = {
row: PropTypes.shape({
calories: PropTypes.number.isRequired,
carbs: PropTypes.number.isRequired,
fat: PropTypes.number.isRequired,
history: PropTypes.arrayOf(
PropTypes.shape({
amount: PropTypes.number.isRequired,
customerId: PropTypes.string.isRequired,
date: PropTypes.string.isRequired,
})
).isRequired,
name: PropTypes.string.isRequired,
price: PropTypes.number.isRequired,
protein: PropTypes.number.isRequired,
}).isRequired,
};
const rows = [
createData("Frozen yoghurt", 159, 6.0, 24, 4.0, 3.99),
createData("Ice cream sandwich", 237, 9.0, 37, 4.3, 4.99),
createData("Eclair", 262, 16.0, 24, 6.0, 3.79),
createData("Cupcake", 305, 3.7, 67, 4.3, 2.5),
createData("Gingerbread", 356, 16.0, 49, 3.9, 1.5),
];
export default function CollapsibleTable() {
return (
<TableContainer component={Paper}>
<Table aria-label="collapsible table">
<TableHead>
<TableRow>
<TableCell />
<TableCell>Dessert (100g serving)</TableCell>
<TableCell align="right">Calories</TableCell>
<TableCell align="right">Fat (g)</TableCell>
<TableCell align="right">Carbs (g)</TableCell>
<TableCell align="right">Protein (g)</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<Row key={row.name} row={row} />
))}
</TableBody>
</Table>
</TableContainer>
);
}