0

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&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

1 Answer 1

0

Set a variable outside of your components with the styles for your row:

const rowStyles = {{ ... }}}

then apply it to both the outer and inner rows:

<TableRow sx={rowStyles}>

3
  • i am already doing something like this. can u please check codesandbox and modify it?
    – Rana Faraz
    Commented Jun 25 at 15:12
  • Link doesn't work, it says: > the Sandbox you're trying to access doesn't exist or you don't have the required permissions to access it.
    – Lee Wise
    Commented Jun 25 at 17:25
  • sorry, please check now codesandbox.io/p/sandbox/epic-breeze-xvzykk
    – Rana Faraz
    Commented Jun 25 at 17:32

Not the answer you're looking for? Browse other questions tagged or ask your own question.