Categories
React Answers

How to Add Table Rows that are Selectable on Click with React Table?

Spread the love

Sometimes, we want to add table rows that are selectable on click with React Table

In this article, we’ll look at how to add table rows that are selectable on click with React Table.

Add Table Rows that are Selectable on Click with React Table

To add table rows that are selectable on click with React Table, we can customize the columns to add a checkbox to the left of the other items.

Then we can pass props to that to make it select the rows.

For instance, we can write:

import React from "react";
import { useTable, useRowSelect } from "react-table";
import namor from "namor";

const range = (len) => {
  const arr = [];
  for (let i = 0; i < len; i++) {
    arr.push(i);
  }
  return arr;
};

const newPerson = () => {
  return {
    firstName: namor.generate({ words: 1, numbers: 0 }),
    lastName: namor.generate({ words: 1, numbers: 0 }),
    age: Math.floor(Math.random() * 30)
  };
};

const makeData = (...lens) => {
  const makeDataLevel = (depth = 0) => {
    const len = lens[depth];
    return range(len).map((d) => {
      return {
        ...newPerson(),
        subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined
      };
    });
  };

return makeDataLevel();
};

const IndeterminateCheckbox = React.forwardRef(
  ({ indeterminate, ...rest }, ref) => {
    const defaultRef = React.useRef();
    const resolvedRef = ref || defaultRef;

React.useEffect(() => {
      resolvedRef.current.indeterminate = indeterminate;
    }, [resolvedRef, indeterminate]);

    return (
      <>
        <input type="checkbox" ref={resolvedRef} {...rest} />
      </>
    );
  }
);

function Table({ columns, data }) {
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    selectedFlatRows,
    state: { selectedRowIds }
  } = useTable(
    {
      columns,
      data
    },
    useRowSelect,
    (hooks) => {
      hooks.visibleColumns.push((columns) => [
        {
          id: "selection",

          Header: ({ getToggleAllRowsSelectedProps }) => (
            <div>
              <IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
            </div>
          ),

Cell: ({ row }) => (
            <div>
              <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
            </div>
          )
        },
        ...columns
      ]);
    }
  );

  return (
    <>
      <table {...getTableProps()}>
        <thead>
          {headerGroups.map((headerGroup) => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((column) => (
                <th {...column.getHeaderProps()}>{column.render("Header")}</th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {rows.slice(0, 10).map((row, i) => {
            prepareRow(row);
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map((cell) => {
                  return (
                    <td {...cell.getCellProps()}>{cell.render("Cell")}</td>
                  );
                })}
              </tr>
            );
          })}
        </tbody>
      </table>
      <p>Selected Rows: {Object.keys(selectedRowIds).length}</p>
      <pre>
        <code>
          {JSON.stringify(
            {
              selectedRowIds: selectedRowIds,
              "selectedFlatRows[].original": selectedFlatRows.map(
                (d) => d.original
              )
            },
            null,
            2
          )}
        </code>
      </pre>
    </>
  );
}

export default function App() {
  const columns = React.useMemo(
    () => [
      {
        Header: "Name",
        columns: [
          {
            Header: "First Name",
            accessor: "firstName"
          },
          {
            Header: "Last Name",
            accessor: "lastName"
          }
        ]
      },
      {
        Header: "Info",
        columns: [
          {
            Header: "Age",
            accessor: "age"
          }
        ]
      }
    ],
    []
  );

  const data = React.useMemo(() => makeData(10, 3), []);

  return <Table columns={columns} data={data} />;
}

We create some data with the makeData function, which calls newPerson to return some randomly generated data.

Then we create the IndeterminateCheckbox component that renders a checkbox that is assigned the ref that we get from the 2nd parameter.

We also pass in the rest props from the first parameter.

This will let us select rows with the checkbox.

Then in the Table component, we render the data.

We set the Header property to a function that renders the IndeterminateCheckbox with the props that we get from getToggleAllRowProps .

Likewise, we set the Cell property to a function that renders the IndeterminateCheckbox with the props that we get from getToggleRowSelectedProps .

We put that before columns so that it’ll be rendered on the leftmost column.

Then in the return statement, we render the table contents.

selectedRowIds has the IDs of the selected row.

And selectedFlatRows has the data of the selected rows.

Conclusion

To add table rows that are selectable on click with React Table, we can customize the columns to add a checkbox to the left of the other items.

Then we can pass props to that to make it select the rows.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *