Type to generate UI components from text

OR

Browse thousands of MUI, Tailwind, React components that are fully customizable and responsive.

Explore Components

How to Effectively Use React Table in Your Projects

React Table is a widely used table library in the React ecosystem, renowned for its simplicity, flexibility, and extensibility. With over 23,000 stars on GitHub, it continues to receive regular updates and supports modern JavaScript features like hooks. This article aims to provide a comprehensive guide on mastering React Table, taking you from the basics to advanced usage.

In this guide, we’ll explore the installation and setup of React Table, its advanced features, extending its functionality with plugins, and compare it with other libraries. By the end of this article, you’ll have a deeper understanding of React Table and how to effectively use it in your projects.

Understanding React Table

React Table is a headless UI library for building powerful, customizable data grids in React. It’s one of the most widely used table libraries in the React ecosystem, boasting over 23k stars on GitHub and receiving frequent updates. It supports modern JavaScript features like hooks, which makes it a preferred choice among developers.

React Table is often referred to as a “headless” library because it provides all the data handling capabilities in a convenient format but leaves the styling and componentizing to the developers. This gives developers complete control over the table’s UI design and styling.

Creating tables can be time consuming, however with tools like PureCode AI, can help cater for that and speed up your development process. It will save you valuable time and effort on a project by providing customized, and ready-to-use components which will allow you to prioritize more important and thought-intensive tasks to speed up the development of your user interface.

Advantages of Using React Table

React Table offers several advantages that make it a valuable tool for developers:

  • Enhanced Performance: React Table optimizes rendering and data manipulation by leveraging virtualization techniques. It only renders the visible rows, significantly reducing the initial load time and improving overall performance.

  • Extensive Feature Set: React Table offers a wide range of features, including column sorting, filtering, pagination, row selection, column reordering, and more. These features empower developers to create dynamic and interactive tables with ease.

  • Customization Options: React Table provides a high level of flexibility for customization. Developers can easily style the table, define custom renderers for cells, headers, and rows, and adapt the behavior to match the specific requirements of their application.

  • Developer-Friendly API: React Table’s API is designed to be developer-friendly and intuitive. It follows the principles of React, making it easy for React developers to integrate and work with the library.

Key Features of React Table

React Table comes with a host of features that make it an excellent choice for managing data in tables:

  • Lightweight: React Table is quite lightweight, with the size being about 5kb – 14kb+.

  • Hooks Compatible: It works well with hooks, which makes it easier to incorporate into modern React applications.

  • Fully Customizable: You can customize everything, from JSX, templates, state, styles, to callbacks.

  • No Data Call Influence: React Table does not perform data calls; it simply uses the passed-in data.

  • Filtering: It supports both global and column filtering.

  • Sorting: It supports sorting for each column based on different data types (numbers, strings, boolean, select input, etc.).

  • Pagination: It supports pagination for long tables.

  • Nested/Grouped Headers: It allows for nested or grouped headers, which can be useful for complex data structures.

When to Use React Table

React Table is generally recommended when you need a simple table with small data and basic features like sorting, global filtering, column filtering, and pagination. It’s also advisable when you want complete control over the table’s UI design and styling. However, as a headless UI library, it requires developers to manage certain aspects like responsiveness and scrolling, especially when dealing with large datasets.

Installing and Setting Up React Table

Before installing React Table, you need to create a new React application. You can do this using the create-react-app command-line tool. Open your terminal, navigate to the directory where you want to create your new project, and run the following command:

npx create-react-app react-table-demo

This command creates a new directory named react-table-demo with a barebones React application inside it. Once the command finishes executing, navigate into your new project directory with

cd react-table-demo

After that spin up your local server by running the code below:

npm start

Installing React Table

Now that you have a React application ready, you can add React Table to your project. Run the following command in your terminal:

npm install react-table

This command adds React Table to your project’s dependencies

Creating a Basic Table with React Table

Let’s start by creating a basic table using React Table. First, import the useTable hook from the library at the top of your file:

import React from 'react';
import { useTable } from 'react-table';

Next, define your data and columns. Your data should be an array of objects, where each object represents a row in the table. Your columns should be an array of objects, where each object defines a column in the table. Here, we define our data and columns using the useMemo hook to ensure that they are only recalculated when necessary.

The columns array consists of objects that define the columns of our table. Each object has a Header property, which is the label that will be displayed in the column header, and an accessor property, which is the key of the data object that this column corresponds to.

const data = React.useMemo(
    () => [
      {
        col1: 'John Doe',
        col2: '25',
        col3: 'john.doe@gmail.com',
      },
      {
        col1: 'Jane Smith',
        col2: '30',
        col3: 'jane.smith@gmail.com',
      },
      // Add more data rows as needed
    ],
    []
  );

  const columns = React.useMemo(
    () => [
      {
        Header: 'Name',
        accessor: 'col1', // accessor is the "key" in the data
      },
      {
        Header: 'Age',
        accessor: 'col2',
      },
      {
        Header: 'Email',
        accessor: 'col3', // accessor is the "key" in the data
      },
    ],
    []
  );

The useTable hook is then called with our columns and data arrays. This hook returns an object with several properties that we use to construct our table. The getTableProps, getTableBodyProps, and getHeaderGroupProps methods return the necessary props for the table element and its children. The headerGroups array contains all the column groups, and the rows array contains all the rows. The prepareRow function prepares a row for rendering.

const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
    useTable({ columns, data });

Finally, we render our table in the return statement of our component. We spread the props returned by the getTableProps method onto our table element, and we map over the headerGroups and rows arrays to render our table headers and body.

<table {...getTableProps()} style={{ border: 'solid 1px black' }}>
      <thead>
        {headerGroups.map((headerGroup) => (
          <tr {...headerGroup.getHeaderGroupProps()}>
            {headerGroup.headers.map((column) => (
              <th
                {...column.getHeaderProps()}
                style={{
                  borderBottom: 'solid 3px red',
                  color: 'black',
                }}
              >
                {column.render('Header')}
              </th>
            ))}
          </tr>
        ))}
      </thead>
      <tbody {...getTableBodyProps()}>
        {rows.map((row) => {
          prepareRow(row);
          return (
            <tr {...row.getRowProps()}>
              {row.cells.map((cell) => {
                return (
                  <td
                    {...cell.getCellProps()}
                    style={{
                      padding: '10px',
                      border: 'solid 1px gray',
                    }}
                  >
                    {cell.render('Cell')}
                  </td>
                );
              })}
            </tr>
          );
        })}
      </tbody>
    </table>

If you further want to learn more about React Table, check out this introductory video:

Advanced Features of React Table

In this section, you will be implementing some table features in your React Table. They include sorting, filtering and pagination functionalities.

Add Sorting Functionality to your React Table

React Table provides a hook called useSortBy that enables you to sort your table by clicking on the column headers. To implement sorting, you need to modify the useTable hook call in your component to include the useSortBy hook.

Step 1: Creating the Table Component

First you will need to create a table component called Table.jsx, where all the code for your table will live. We’ll use the useTable and useSortBy hooks from react-table to provide the main functionality for the table and add sorting capabilities.

First, import the useSortBy hook at the top of your file:

import { useTable, useSortBy } from 'react-table';

Then, modify the useTable hook call to include useSortBy:

const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable(
 {
   columns,
   data,
 },
 useSortBy
);

Here’s what the initial structure of our table component might look like:

import React from 'react';
import { useTable, useSortBy } from 'react-table';

function Table({ columns, data }) {
 const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
 } = useTable({ columns, data }, useSortBy);

 return (
    <table {...getTableProps()} style={{margin: 'auto'}}>
	// table header
      <thead>
        {headerGroups.map(headerGroup => (
          <tr {...headerGroup.getHeaderGroupProps()}>
            {headerGroup.headers.map(column => (
              <th
                {...column.getHeaderProps(column.getSortByToggleProps())}
              >
                {column.render('Header')}
                <span>
                 {column.isSorted
                    ? column.isSortedDesc
                      ? ' 🔽'
                      : ' 🔼'
                    : ''}
                </span>
              </th>
            ))}
          </tr>
        ))}
      </thead>
      <tbody {...getTableBodyProps()}>
        {rows.map(row => {
          prepareRow(row);
          return (
            <tr {...row.getRowProps()}>
              {row.cells.map(cell => {
                return (
                 <td {...cell.getCellProps()}>
                    {cell.render('Cell')}
                 </td>
                )
              })}
            </tr>
          )
        })}
      </tbody>
    </table>
 );
}

export default Table;

Step 2: Defining the Columns and Data

Next, we need to define the columns and data for our table. The columns array contains objects representing each column in the table, and the accessor property of each column object determines what piece of data from the data array will be displayed in that column.

Here’s an example of defining the columns and data:

const columns = [
 {
    Header: 'Name',
    accessor: 'name',
 },
 {
    Header: 'Age',
    accessor: 'age',
 },
 {
    Header: 'Gender',
    accessor: 'gender',
 },
 // Add more columns as needed
];

const data = [
 { name: 'John', age: 28, gender: 'Male' },
 { name: 'Jane', age: 24, gender: 'Female' },
 // Add more data rows as needed
];

Step 3: Using the Table Component

Finally, we can use the Table component in our app. We just need to pass the columns and data arrays as props to the Table component:

import React from 'react';
import Table from './Table';

function App() {
 return (
    <div className="App">
      <Table columns={columns} data={data} />
    </div>
 );
}

export default App;

And that’s it! Now we have a table with sorting functionality. When you click on a column header, the table will sort the data in ascending or descending order based on the values in that column. Clicking the same header again will reverse the sort order. You can add some styling to make your table responsive.

Adding Filter Functionality to your React Table

Let’s add filter functionality to our table using react-table. We’ll add both global filtering (a single input field that filters across all columns) and individual column filtering (an input field for each column).

Step 1: Importing Required Hooks

We need to import the useFilters, useGlobalFilter, and useAsyncDebounce hooks from react-table:

import { useTable, useFilters, useGlobalFilter, useAsyncDebounce } from 'react-table';

Step 2: Defining Filters

We’ll create two separate components for our filters – one for the global filter and one for the individual column filters:

Global Filter

The global filter will allow us to filter the entire table at once. We’ll create a controlled input field that updates the global filter whenever its value changes:

function GlobalFilter({
    preGlobalFilteredRows,
    globalFilter,
    setGlobalFilter,
}) {
    const count = preGlobalFilteredRows.length;
    const [value, setValue] = React.useState(globalFilter);
    const onChange = useAsyncDebounce(value => {
        setGlobalFilter(value || undefined);
    }, 200);

    return (
        <span>
            Search:{' '}
            <input
                className="form-control"
                value={value || ""}
                onChange={e => {
                    setValue(e.target.value);
                    onChange(e.target.value);
                }}
                placeholder={`${count} records...`}
            />
        </span>
    );
}
Individual Column Filters

The individual column filters will allow us to filter each column independently. We’ll create a similar controlled input field for each column:

function DefaultColumnFilter({
    column: { filterValue, preFilteredRows, setFilter },
}) {
    const count = preFilteredRows.length;

    return (
        <input
            className="form-control"
            value={filterValue || ''}
            onChange={e => {
                setFilter(e.target.value || undefined);
            }}
            placeholder={`Search ${count} records...`}
        />
    );
}

Step 3: Adding Filters to the Table

Now we can add our filters to the table. We’ll use the useFilters and useGlobalFilter hooks from react-table to enable filtering functionality:

function Table({ columns, data }) {
    const defaultColumn = React.useMemo(
        () => ({
            // Default Filter UI
            Filter: DefaultColumnFilter,
        }),
        []
    );

    const {
        getTableProps,
        getTableBodyProps,
        headerGroups,
        rows,
        prepareRow,
        state,
        preGlobalFilteredRows,
        setGlobalFilter,
    } = useTable(
        {
            columns,
            data,
            defaultColumn
        },
        useFilters,
        useGlobalFilter
    );

    // ... rest of the component
}

In the above code, we’ve added the useFilters and useGlobalFilter hooks to the useTable hook. We’ve also defined a defaultColumn object that specifies the default filter UI for each column.

Step 4: Rendering Filters

Finally, we can render our filters in the table. We’ll render the global filter above the table, and each individual column filter in the corresponding column header:

return (
    <div>
        <GlobalFilter
            preGlobalFilteredRows={preGlobalFilteredRows}
            globalFilter={state.globalFilter}
            setGlobalFilter={setGlobalFilter}
        />
        <table className="table" {...getTableProps()}>
            <thead>
                {headerGroups.map(headerGroup => (
                    <tr {...headerGroup.getHeaderGroupProps()}>
                        {headerGroup.headers.map(column => (
                            <th {...column.getHeaderProps()}>
                                {column.render('Header')}
                                {/* Render the columns filter UI */}
                                <div>{column.canFilter ? column.render('Filter') : null}</div>
                            </th>
                        ))}
                    </tr>
                ))}
            </thead>
            {/* ... rest of the table */}
        </table>
    </div>
);

In the above code, we’ve rendered the GlobalFilter component above the table, and each column’s filter UI inside the corresponding column header. The column.canFilter check ensures that a filter UI is only rendered for columns that can be filtered.

Here is the complete code for the filter functionality

import React from 'react';
import {
  useTable,
  useSortBy,
  useFilters,
  useGlobalFilter,
  useAsyncDebounce,
} from 'react-table';

function Table({ columns, data }) {
    const defaultColumn = React.useMemo(
      () => ({
        // Default Filter UI
        Filter: DefaultColumnFilter,
      }),
      []
    );

    const {
      getTableProps,
      getTableBodyProps,
      headerGroups,
      rows,
      prepareRow,
      state,
      preGlobalFilteredRows,
      setGlobalFilter,
    } = useTable(
      {
        columns,
        data,
        defaultColumn,
      },
      useFilters,
      useGlobalFilter
    );

  function GlobalFilter({
    preGlobalFilteredRows,
    globalFilter,
    setGlobalFilter,
  }) {
    const count = preGlobalFilteredRows.length;
    const [value, setValue] = React.useState(globalFilter);
    const onChange = useAsyncDebounce((value) => {
      setGlobalFilter(value || undefined);
    }, 200);

    return (
      <span>
        Search:{' '}
        <input
          className="form-control"
          value={value || ''}
          onChange={(e) => {
            setValue(e.target.value);
            onChange(e.target.value);
          }}
          placeholder={`${count} records...`}
        />
      </span>
    );
  }

  function DefaultColumnFilter({
    column: { filterValue, preFilteredRows, setFilter },
  }) {
    const count = preFilteredRows.length;

    return (
      <input
        className="form-control"
        value={filterValue || ''}
        onChange={(e) => {
          setFilter(e.target.value || undefined);
        }}
        placeholder={`Search ${count} records...`}
      />
    );
  }



  return (
    <div>
      <GlobalFilter
        preGlobalFilteredRows={preGlobalFilteredRows}
        globalFilter={state.globalFilter}
        setGlobalFilter={setGlobalFilter}
      />
      <table className="table" {...getTableProps()} style={{ margin: 'auto' }}>
        {headerGroups.map(headerGroup => (
                    <tr {...headerGroup.getHeaderGroupProps()}>
                        {headerGroup.headers.map(column => (
                            <th {...column.getHeaderProps()}>
                                {column.render('Header')}
                                {/* Render the columns filter UI */}
                                <div>{column.canFilter ? column.render('Filter') : null}</div>
                            </th>
                        ))}
                    </tr>
                ))}
        <tbody {...getTableBodyProps()}>
          {rows.map((row) => {
            prepareRow(row);
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map((cell) => {
                  return (
                    <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
                  );
                })}
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}
export default Table;

Adding Pagination to your React Table

Let’s add pagination functionality to our table using react-table. We’ll allow the user to control the number of rows displayed per page and navigate between different pages.

Step 1: Importing Required Hooks

First, we need to import the usePagination hook from react-table:

import { useTable, usePagination } from 'react-table';

Step 2: Adding Pagination to the Table

We can now add the usePagination hook to the useTable hook to enable pagination functionality:

function Table({ columns, data }) {
    const {
        getTableProps,
        getTableBodyProps,
        headerGroups,
        prepareRow,
        page,
        canPreviousPage,
        canNextPage,
        nextPage,
        previousPage,
        state: { pageIndex, pageSize },
    } = useTable(
        {
            columns,
            data,
        },
        usePagination
    );

    // ... rest of the component for your own table markup/table data
}

In the above code, usePagination provides several variables that we can use to control pagination. page contains the current page’s rows, canPreviousPage and canNextPage indicate whether there are previous or next pages, nextPage and previousPage are functions to go to the next or previous page, and pageIndex and pageSize represent the current page index and the number of rows per page.

Step 3: Setting Page Size

To implement pagination functionality with a maximum of 5 data items per page, we need to adjust the pageSize parameter in the useTable hook. This parameter controls the number of rows displayed per page. Here is how

function Table({ columns, data }) {
    const {
        getTableProps,
        getTableBodyProps,
        headerGroups,
        prepareRow,
        page,
        canPreviousPage,
        canNextPage,
        nextPage,
        previousPage,
        state: { pageIndex, pageSize },
    } = useTable(
        {
            columns,
            data,
            initialState: { pageIndex: 0, pageSize: 5 },
        },
        usePagination
    );
}

In the above code, initialState: { pageIndex: 0, pageSize: 5 } sets the initial page size to 5.

Step 4: Rendering Rows

Next, we need to adjust the rendering of rows to use the page variable provided by useTable. This variable contains the current page’s rows:

return (
    <div>
        <table className="table" {...getTableProps()}>
            {/* ... rest of the table */}
            <tbody {...getTableBodyProps()}>
                {page.map(row => {
                    prepareRow(row);
                    return (
                        <tr {...row.getRowProps()}>
                            {row.cells.map(cell => {
                                return (
                                    <td {...cell.getCellProps()}>
                                        {cell.render('Cell')}
                                    </td>
                                )
                            })}
                        </tr>
                    )
                })}
            </tbody>
        </table>
        {/* ... rest of the component */}
    </div>
);

In the above code, page.map(row => {…}) maps over the rows in the current page and renders them.

Step 5: Rendering Pagination Controls

Finally, we can render the pagination controls below the table. These controls will allow the user to navigate between pages and change the number of rows displayed per page:

return (
    <div>
        <table className="table" {...getTableProps()}>
            {/* ... rest of the table */}
        </table>
        <div className="pagination">
            <button onClick={() => previousPage()} disabled={!canPreviousPage}>
                {'<'}
            </button>
            <span>
                Page{' '}
                <strong>
                    {pageIndex + 1} of {Math.ceil(page.length / pageSize)}
                </strong>
            </span>
            <button onClick={() => nextPage()} disabled={!canNextPage}>
                {'>'}
            </button>
        </div>
    </div>
);

In the above code, we’ve rendered two buttons for navigating between pages and a span displaying the current page number and total number of pages. The onClick handlers call the previousPage and nextPage functions to change the page, and the disabled attributes disable the buttons if there are no previous or next pages.

Learn more about React Table from this video

Extending Functionality with Plugins

React Table allows you to extend its functionality through plugins. These plugins can add new features or modify existing ones. However, unlike traditional plugins, React Table doesn’t have a dedicated plugin system. Instead, you extend its functionality by wrapping the useTable hook with your own function.

Creating a Custom Hook

To create a custom hook, you simply create a new function that takes the same arguments as useTable and returns the same output. Here’s an example of a custom hook that extends the functionality of useTable:

function useMyTable(options) {
 const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable(options);

 // Add your custom functionality here

 return { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow };
}

In this example, useMyTable is a function that behaves exactly like useTable. You can add your custom functionality to this function.

Using a Custom Hook

Once you’ve created your custom hook, you can use it just like you would use useTable. Here’s an example:

const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useMyTable({ columns, data });

In this example, useMyTable is used instead of useTable. This means that the table will have all the functionality of useTable, plus any additional functionality that you added in your custom hook.

Adding Additional Functionality

If you want to add additional functionality to an existing hook, such as useSortBy or useRowSelect, you can do so by pushing your custom hook onto the useInstance hook . Here’s an example:

function useMySortBy(hooks) {
 useSortBy(hooks);
 hooks.useInstance.push(useInstance);
}

function useInstance(instance) {
 // Add your custom table instance functionality here
}

In this example, useMySortBy is a function that first calls useSortBy to add sorting functionality, and then pushes useInstance onto the useInstance hook to add additional functionality.

React Table vs Other Libraries

There are numerous libraries available for building tables in React. While React Table is a popular choice due to its flexibility, simplicity, and extensive feature set, it’s worth comparing it with other libraries to understand its strengths and weaknesses.

Material React Table

One alternative to React Table is Material React Table. This library is built directly on top of Material UI and TanStack Table (formerly known as React Table). It offers a rich set of features, including filtering, sorting, and grouping, and is very customizable and flexible. It also has a small bundle size, making it a lighter weight alternative to other libraries.

However, Material React Table requires knowledge of Material UI, which might not be suitable for all projects. Also, while it offers a wide range of features, it might be overkill for simple tables.

React Bootstrap Table2

React Bootstrap Table2 is another alternative that provides a cleaner design and a small bundle size. It’s particularly useful if you’re using Bootstrap based UI components in your React app. It supports basic features such as sorting, and you can add more advanced features like pagination by installing a separate component library.

However, React Bootstrap Table2 has limited support for advanced features compared to other libraries. It also lacks support for virtualization, which could impact performance with large datasets.

React Virtualized

React Virtualized is a multi-purpose component library that supports the rendering of large lists and data tables. It supports various formats such as grid, masonry, list, and collection. However, it has a steeper learning curve due to its feature-rich nature and requires some effort to set up initially.

Check out this React table tutorial series

Best Practices for using React Table library

Best PracticeDescription
Choose the Right LibraryConsider the features your table needs and choose the library that fits those needs. If you need a simple page with a small amount of data, custom styles, and basic features like sorting and filtering, React Table is a good choice 1.
Optimize PerformanceGood user experience often depends on application speed. React Table optimizes rendering and data manipulation by leveraging virtualization techniques. It only renders the visible rows, significantly reducing the initial load time and improving overall performance 1.
Customize Your TableReact Table is a headless UI library, meaning it provides all the data handling capabilities but leaves the styling and componentizing to the developers. This gives you complete control over the table’s UI design and styling 2.
Use Hooks for FlexibilityReact Table works well with hooks, which makes it easier to incorporate into modern React applications. It offers a variety of hooks to add functionalities like sorting, filtering, and pagination 2.
Handle Large Datasets CarefullyWhile React Table is capable of handling large datasets, it requires developers to manage certain aspects like responsiveness and scrolling, especially when dealing with extensive data 3.
Use Plugins for Extended FunctionalityReact Table allows you to extend its functionality through plugins. These plugins can add new features or modify existing ones, enhancing the functionality of your table 2.
Keep Documentation CloseRegularly refer to the official documentation and community resources for guidance and troubleshooting. The React Table community is active and supportive, and the documentation is well-maintained and comprehensive 2.

What have we learned so far?

React Table is a versatile and powerful library that can greatly enhance your ability to handle tabular data in React applications. It offers a range of features, from sorting and filtering to pagination, and its flexibility allows you to customize it to suit your specific needs. However, like any tool, it’s important to understand its strengths and limitations, and use it appropriately in your projects.

While React Table provides a solid foundation for creating tables, it might not alway be the best choice for every scenario. Depending on your project’s requirements, other libraries like Material React Table, React Bootstrap Table2, or React Virtualized might be more suitable. Therefore, it’s crucial to evaluate each library based on your specific needs, such as the complexity of your tables, the size of your datasets, and your preferred design system. Always remember to consider factors like the library’s customizability, performance, and community support when choosing a table library for your React project.

We at Purecode AI have simplified the process of building web applications by leveraging the power of AI to quickly and effortlessly generate top-quality components for your CSS, Tailwind CSS, Material UI, and React applications. Check out our repository of over 10, 000 components ready to be integrated and x20 development your speed 🚀

Further Readings

If you enjoyed reading this piece, do check out some other articles from our blog:

Victor Yakubu

Victor Yakubu