OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

how to keep the nested collapsible table row inside main tabe row in mui table react?

  • Thread starter Thread starter Rana Faraz
  • Start date Start date
R

Rana Faraz

Guest
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/confident-wiles-tpqwdl?file=/src/Demo.js

Code:
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&nbsp;(g)</TableCell>
            <TableCell align="right">Carbs&nbsp;(g)</TableCell>
            <TableCell align="right">Protein&nbsp;(g)</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {rows.map((row) => (
            <Row key={row.name} row={row} />
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
}

enter image description here

<p>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.</p>
<p>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.</p>
<p>I've included the code and a CodeSandbox link for reference. Thank you in advance for your help!
<a href="https://codesandbox.io/p/sandbox/confident-wiles-tpqwdl?file=/src/Demo.js" rel="nofollow noreferrer">https://codesandbox.io/p/sandbox/confident-wiles-tpqwdl?file=/src/Demo.js</a></p>
<pre><code>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&nbsp;(g)</TableCell>
<TableCell align="right">Carbs&nbsp;(g)</TableCell>
<TableCell align="right">Protein&nbsp;(g)</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<Row key={row.name} row={row} />
))}
</TableBody>
</Table>
</TableContainer>
);
}
</code></pre>
<p><a href="https://i.sstatic.net/Z4TVrgPm.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/Z4TVrgPm.png" alt="enter image description here" /></a></p>
 

Latest posts

Top