poldeeek
poldeeek

Reputation: 333

validateDOMNesting(...): <tr> cannot appear as a child of <div> problem

I am using material-ui in my react.js project. When I try to test my Row component, I get that console.error:

  Warning: validateDOMNesting(...): <tr> cannot appear as a child of <div>.

Here is my Row component:

const Row: React.FC<RowProps> = ({ course }) => {
  const [open, setOpen] = useState(false);
  const classes = useRowStyles();

  const isDesktopOrLaptop = useMediaQuery({
    query: '(min-device-width: 992px)',
  });

  const boxMargin = isDesktopOrLaptop ? 8 : 1;

  return (
    <>
      <TableRow className={classes.root}>
        <TableCell>
          <IconButton
            aria-label="expand row"
            size="small"
            onClick={() => setOpen(!open)}>
            {open ? (
              <KeyboardArrowUpIcon fontSize="large" />
            ) : (
              <KeyboardArrowDownIcon fontSize="large" />
            )}
          </IconButton>
        </TableCell>
        <TableCell component="th" scope="row">
          <Typography variant="h5" component="h5">
            {course.course}
          </Typography>
        </TableCell>
        <TableCell align="right">
          <Typography variant="h5" component="h5">
            {course.openedLessonsCount}
          </Typography>
        </TableCell>
      </TableRow>
      <TableRow>
        <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
          <Collapse in={open} timeout="auto" unmountOnExit>
            <Box marginX={boxMargin} marginY={1}>
              <Typography variant="h5" gutterBottom component="h5">
                Projects
              </Typography>
              <Table size="small" aria-label="purchases">
                <TableHead>
                  <TableRow>
                    <TableCell>
                      <Typography variant="h6" gutterBottom component="h6">
                        Name
                      </Typography>
                    </TableCell>
                    <TableCell align="right">
                      <Typography variant="h6" gutterBottom component="h6">
                        Completed Lessons
                      </Typography>
                    </TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {course.projects &&
                    course.projects.map((project: IProject) => (
                      <TableRow key={project.project}>
                        <TableCell component="th" scope="row">
                          <Typography variant="body1" gutterBottom>
                            {project.project}
                          </Typography>
                        </TableCell>
                        <TableCell align="right">
                          <Typography variant="body1" gutterBottom>
                            {project.completedLessonsCount}
                          </Typography>
                        </TableCell>
                      </TableRow>
                    ))}
                </TableBody>
              </Table>
            </Box>
          </Collapse>
        </TableCell>
      </TableRow>
    </>
  );
};

And here is generated snapshot for it:

<body>
  <div>
    <tr
      class="MuiTableRow-root makeStyles-root-1"
    >
      <td
        class="MuiTableCell-root"
      >
        <button
          aria-label="expand row"
          class="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeSmall"
          tabindex="0"
          type="button"
        >
          <span
            class="MuiIconButton-label"
          >
            <svg
              aria-hidden="true"
              class="MuiSvgIcon-root MuiSvgIcon-fontSizeLarge"
              focusable="false"
              viewBox="0 0 24 24"
            >
              <path
                d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"
              />
            </svg>
          </span>
          <span
            class="MuiTouchRipple-root"
          />
        </button>
      </td>
      <th
        class="MuiTableCell-root"
        role="cell"
        scope="row"
      >
        <h5
          class="MuiTypography-root MuiTypography-h5"
        >
          Course1
        </h5>
      </th>
      <td
        class="MuiTableCell-root MuiTableCell-alignRight"
      >
        <h5
          class="MuiTypography-root MuiTypography-h5"
        >
          3
        </h5>
      </td>
    </tr>
    <tr
      class="MuiTableRow-root"
    >
      <td
        class="MuiTableCell-root"
        colspan="6"
        style="padding-bottom: 0px; padding-top: 0px;"
      />
    </tr>
  </div>
</body>

So it looks like the problem is the <div> element inside the <body>, but I don't know how to fix that error. I use React.Fragment (<>) to grab these two of TableRow, so that <div> shouldn't exist in my opinion...

That Row component I took from material-ui docs for collapsible table: https://material-ui.com/components/tables/

And there is codesandbox code for it (also from docs): https://codesandbox.io/s/material-demo-forked-fnisr?file=/demo.js

@@ UPDATE

I had to wrap Row component with <table> and <tbody>. I've created a wrapper for that. This is how the test code looks like now:

const Wrapper: React.FC = ({ children }) => {
  return (
    <table>
      <tbody>{children}</tbody>
    </table>
  );
};

test('Basic render', () => {
  const component = render(
    <Wrapper>
      <Row course={props} />
    </Wrapper>
  );
  expect(component.baseElement).toMatchSnapshot();
});

Upvotes: 3

Views: 6934

Answers (3)

Berke Şent&#252;rk
Berke Şent&#252;rk

Reputation: 119

Just wrap your component with tbody

For example,

<table>
  <tbody>
    <tr></tr>
    <tr></tr>
  </tbody>
</table>

Upvotes: 0

hotpink
hotpink

Reputation: 3226

In the demo the rows are wrapped in a table head or table body element, you need to add valid context in your component also.

Contexts in which a tr element can be used:

As a child of a thead element.
As a child of a tbody element.
As a child of a tfoot element.
As a child of a table element, after any caption, colgroup, and thead elements, but only if there are no tbody elements that are children of the table element.

The parent div is not from your custom Row component, but from where you render <Row />.

Upvotes: 1

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85565

The tr element must have parent table element. So, wrapping your component with table will solve the issue.

The tr cannot be descendent of div element.

Upvotes: 1

Related Questions