Skip to content
\n

The output looks like:

\n

\"rowspan\"

\n

So I tried implementing it in CodeSandBox. Following is the code:

\n
import * as React from \"react\";\nimport { useTable } from \"react-table\";\n\nconst borderStyle = {\n  border: \"1px dashed navy\"\n};\n\nexport default function App() {\n  const data = React.useMemo(\n    () => [\n      {\n        actor: \"Johnny Depp\",\n        movies: [\n          {\n            name: \"Pirates of the Carribean 1\"\n          },\n          {\n            name: \"Pirates of the Carribean 2\"\n          },\n          {\n            name: \"Pirates of the Carribean 3\"\n          },\n          {\n            name: \"Pirates of the Carribean 4\"\n          }\n        ]\n      }\n    ],\n    []\n  );\n  const columns = React.useMemo(\n    () => [\n      {\n        Header: \"Actor\",\n        accessor: \"actor\",\n        enableRowSpan: true\n      },\n      {\n        Header: \"Movies\",\n        accessor: (row, index) => {\n          console.log({ row });\n          return row.movies.map(movie => movie.name);\n        }\n      }\n    ],\n    []\n  );\n  const {\n    getTableProps,\n    getTableBodyProps,\n    headerGroups,\n    rows,\n    prepareRow\n  } = useTable({ columns, data });\n  return (\n    <table {...getTableProps()}>\n      <thead>\n        {headerGroups.map(headerGroup => (\n          <tr {...headerGroup.getHeaderGroupProps()}>\n            {headerGroup.headers.map(column => (\n              <th {...column.getHeaderProps()} style={borderStyle}>\n                {column.render(\"Header\")}\n              </th>\n            ))}\n          </tr>\n        ))}\n      </thead>\n      <tbody {...getTableBodyProps()}>\n        {rows.map((row, i) => {\n          prepareRow(row);\n          if (i == 0) {\n            console.log({ row });\n          }\n          return (\n            <tr {...row.getRowProps()}>\n              {row.cells.map((cell, j) => {\n                if (i == 0 && j < 2) {\n                  console.log({ cell, i, j });\n                }\n                return (\n                  <td\n                    rowSpan={cell.rowSpan}\n                    {...cell.getCellProps()}\n                    style={borderStyle}\n                  >\n                    {cell.render(\"Cell\")}\n                  </td>\n                );\n              })}\n            </tr>\n          );\n        })}\n      </tbody>\n    </table>\n  );\n}
\n

Here's the direct link to it: https://codesandbox.io/s/modest-sanderson-z0keq?file=/src/App.tsx

\n

It looks like:

\n

\"codesandbox\"

\n

I want movie names to be one below the other but can't seem to figure it out 🤔

\n

I want it to look like the HTML. The data shouldn't change as my original use-case fetches from an API. How do I do it?

","upvoteCount":2,"answerCount":10,"acceptedAnswer":{"@type":"Answer","text":"

Okay made it work. Guess I just had to flatten the data. It was as easy as just copying & pasting your code. Here's the working solution:

\n
import * as React from \"react\";\nimport { useTable } from \"react-table\";\n\ntype Data = {\n  actor: string;\n  movie: string;\n};\n\nconst borderStyle = {\n  border: \"1px solid gray\",\n  padding: \"8px 10px\"\n};\n\nfunction useInstance(instance) {\n  const { allColumns } = instance;\n\n  let rowSpanHeaders = [];\n\n  allColumns.forEach((column, i) => {\n    const { id, enableRowSpan } = column;\n\n    if (enableRowSpan !== undefined) {\n      rowSpanHeaders = [\n        ...rowSpanHeaders,\n        { id, topCellValue: null, topCellIndex: 0 }\n      ];\n    }\n  });\n\n  Object.assign(instance, { rowSpanHeaders });\n}\n\nexport default function App() {\n  const origData = [\n    {\n      actor: \"Johnny Depp\",\n      movies: [\n        {\n          name: \"Pirates of the Carribean 1\"\n        },\n        {\n          name: \"Pirates of the Carribean 2\"\n        },\n        {\n          name: \"Pirates of the Carribean 3\"\n        },\n        {\n          name: \"Pirates of the Carribean 4\"\n        }\n      ]\n    }\n  ];\n  const newData: Array<Data> = [];\n  origData.forEach(actorObj => {\n    actorObj.movies.forEach(movie => {\n      newData.push({\n        actor: actorObj.actor,\n        movie: movie.name\n      });\n    });\n  });\n  const data = React.useMemo(() => newData, []);\n  const columns = React.useMemo(\n    () => [\n      {\n        Header: \"Actor\",\n        accessor: \"actor\",\n        enableRowSpan: true\n      },\n      {\n        Header: \"Movies\",\n        accessor: \"movie\"\n      }\n    ],\n    []\n  );\n  const {\n    getTableProps,\n    getTableBodyProps,\n    headerGroups,\n    rows,\n    prepareRow,\n    rowSpanHeaders\n  } = useTable({ columns, data }, hooks => {\n    hooks.useInstance.push(useInstance);\n  });\n  return (\n    <table {...getTableProps()}>\n      <thead>\n        {headerGroups.map(headerGroup => (\n          <tr {...headerGroup.getHeaderGroupProps()}>\n            {headerGroup.headers.map(column => (\n              <th {...column.getHeaderProps()} style={borderStyle}>\n                {column.render(\"Header\")}\n              </th>\n            ))}\n          </tr>\n        ))}\n      </thead>\n      <tbody {...getTableBodyProps()}>\n        {rows.map((row, i) => {\n          prepareRow(row);\n\n          for (let j = 0; j < row.allCells.length; j++) {\n            let cell = row.allCells[j];\n            let rowSpanHeader = rowSpanHeaders.find(\n              x => x.id === cell.column.id\n            );\n\n            if (rowSpanHeader !== undefined) {\n              if (\n                rowSpanHeader.topCellValue === null ||\n                rowSpanHeader.topCellValue !== cell.value\n              ) {\n                cell.isRowSpanned = false;\n                rowSpanHeader.topCellValue = cell.value;\n                rowSpanHeader.topCellIndex = i;\n                cell.rowSpan = 1;\n              } else {\n                rows[rowSpanHeader.topCellIndex].allCells[j].rowSpan++;\n                cell.isRowSpanned = true;\n              }\n            }\n          }\n          return null;\n        })}\n        {rows.map(row => {\n          return (\n            <tr {...row.getRowProps()}>\n              {row.cells.map(cell => {\n                if (cell.isRowSpanned) return null;\n                else\n                  return (\n                    <td\n                      style={borderStyle}\n                      rowSpan={cell.rowSpan}\n                      {...cell.getCellProps()}\n                    >\n                      {cell.render(\"Cell\")}\n                    </td>\n                  );\n              })}\n            </tr>\n          );\n        })}\n      </tbody>\n    </table>\n  );\n}
\n

\"react-table-row-span\"

\n

And here's the link to Codesandbox 👉 https://codesandbox.io/s/flattening-row-with-react-table-prkqb?file=/src/App.tsx

\n

Thank you @liberza 🙌

","upvoteCount":8,"url":"https://github.com/TanStack/table/discussions/2233#discussioncomment-12415"}}}
Discussion options

You must be logged in to vote

Okay made it work. Guess I just had to flatten the data. It was as easy as just copying & pasting your code. Here's the working solution:

import * as React from "react";
import { useTable } from "react-table";

type Data = {
  actor: string;
  movie: string;
};

const borderStyle = {
  border: "1px solid gray",
  padding: "8px 10px"
};

function useInstance(instance) {
  const { allColumns } = instance;

  let rowSpanHeaders = [];

  allColumns.forEach((column, i) => {
    const { id, enableRowSpan } = column;

    if (enableRowSpan !== undefined) {
      rowSpanHeaders = [
        ...rowSpanHeaders,
        { id, topCellValue: null, topCellIndex: 0 }
      ];
    }
  });

  Object.assign(i…

Replies: 10 comments 29 replies

Comment options

You must be logged in to vote
0 replies
Comment options

You must be logged in to vote
0 replies
Comment options

You must be logged in to vote
15 replies
@michaelsawyers
Comment options

@kapoor17
Comment options

@mindkeeper
Comment options

@AdnanTheExcellent
Comment options

@michaelsawyers
Comment options

Answer selected by deadcoder0904
Comment options

You must be logged in to vote
3 replies
@nleve
Comment options

@nleve
Comment options

@tvone
Comment options

Comment options

You must be logged in to vote
7 replies
@ljubomirsinadinovski
Comment options

@aliabdollahy
Comment options

@noorqidam
Comment options

@ljubomirsinadinovski
Comment options

@azhoang-sts
Comment options

Comment options

You must be logged in to vote
0 replies
Comment options

You must be logged in to vote
0 replies
Comment options

You must be logged in to vote
4 replies
@deadcoder0904
Comment options

@tushar1998
Comment options

@itskazemk
Comment options

@tushar1998
Comment options

Comment options

You must be logged in to vote
0 replies
Comment options

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet