How to implement Datatable in React with Example

78169 views 2 years ago React

In this tutorial, we are going to learn in easy ways how to build data tables in React web application from scratch using react-table package.

If you are beginner, then i will recommend going through following tutorials to get started with react:

Data table is very useful UI component, It helps in managing the complex set of data in any web or mobile application. A user can easily visualize, compare, sort, filter and scan information using a data table.

React 16+ Table Tutorial with Example

We are going to use react-table package to create a data table in React. We will learn to implement essential features of react-table library that helps to show the data in an organized way.

The react-table package is widely used data table third party package for React framework. This library is extremely light and provides almost all the basic table features which are necessary to display the complex information to the users.

Setting up React Project

Run the following command to install React app using create-react-app.

npx create-react-app react-table-tutorial

Start the app using below command:

npm start

You can view your app on: localhost:3000

Install react-table in React App

We are going to use the react-table plugin to build the data table component in our React app.

Install React Table, run either of the command based on your package manager:

# NPM
$ npm install react-table
# Yarn
$ yarn add react-table

We also need to install the styled-components using the following command:

styled-components

Build Data Table in React with react-table

Once we are done installing react-table in our React table application. Then we need to import the useTable API at the top of the src/App.js component.

import {useTable} from 'react-table';

Next, import the styled-component package, It allows you to write actual CSS code to style your React or React Native components.

npm i styled-components

Add the code in the App.js component to design our data table.

const Styles = styled.div `
  table {
    width: 100%;
    border-spacing: 0;
    border: 1px solid black;
    tr {
      :last-child {
        td {
          border-bottom: 0;
        }
      }
    }
    th,
    td {
      margin: 0;
      padding: 1rem;
      border-bottom: 1px solid black;
      border-right: 1px solid black;
      :last-child {
        border-right: 0;
      }
    }
  }
`

Create Table UI

Next, we will define the Table method and pass columns, data value into it. This method helps in rendering the data table UI, we have also declared the state and methods returned via useTable API to create the data table component in React.

function Table({columns, data}) {
  const {getTableProps, getTableBodyProps, headerGroups, rows, prepareRow} = useTable({columns, data})
  // Render Data Table UI
  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.map((row, i) => {
          prepareRow(row);
          return (
            <tr {...row.getRowProps()}>
              {row
                .cells
                .map(cell => {
                  return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
                })}
            </tr>
          )
        })}
      </tbody>
    </table>
  )
}

We must have some data that will be rendered by the react-table package in the React data table component.

const data = [
    {
      name: 'Leanne Graham',
      email: '[email protected]',
      age: 28,
      status: 'Active'
    },
    {
      name: 'Ervin Howell',
      email: '[email protected]',
      age: 35,
      status: 'Active'
    },
    {
      name: 'Clementine Bauch',
      email: '[email protected]',
      age: 33,
      status: 'Inactive'
    },
    {
      name: 'Patricia Lebsack',
      email: '[email protected]',
      age: 25,
      status: 'Active'
    },
    {
      name: 'Kamren',
      email: '[email protected]',
      age: 42,
      status: 'Active'
    },
    {
      name: 'Dennis Schulist',
      email: '[email protected]',
      age: 34,
      status: 'Inactive'
    },
    {
      name: 'Kurtis Weissnat',
      email: '[email protected]',
      age: 44,
      status: 'Active'
    },
    {
      name: 'Maxime_Nienow',
      email: '[email protected]',
      age: 26,
      status: 'Active'
    },
    {
      name: 'Glenna Reichert',
      email: '[email protected]',
      age: 30,
      status: 'Inactive'
    },                                
  ]

We must define the column directive and ad the column data, add the following code in the App.js file.

The ReactTable will render the data array by mapping the JSON data key associated with column accessor value. For example, our column headers values in table are Name, Email, Age, and Status.

const columns = [
    {
      Header: 'Name',
      accessor: 'name'
    }, {
      Header: 'Email',
      accessor: 'email'
    }, {
      Header: 'Age',
      accessor: 'age'
    }, {
      Header: 'Status',
      accessor: 'status'
    }
]

Inside the return method define the Styles attribute to style the table UI, then set the Table attribute along with table properties to render the JSON data in the React table.

return (
    <Styles>
      <Table
        data={data}
        columns={columns}
      />
    </Styles>
  )

Above code will successfully display the rows of data along with the data values as column header.

Here is how the final App component looks in the src/App.js file:

import React from 'react';
import {useTable} from 'react-table'
import styled from 'styled-components'
const Styles = styled.div `
  table {
    width: 100%;
    border-spacing: 0;
    border: 1px solid black;
    tr {
      :last-child {
        td {
          border-bottom: 0;
        }
      }
    }
    th,
    td {
      margin: 0;
      padding: 1rem;
      border-bottom: 1px solid black;
      border-right: 1px solid black;
      :last-child {
        border-right: 0;
      }
    }
  }
`
function Table({columns, data}) {
  const {getTableProps, getTableBodyProps, headerGroups, rows, prepareRow} = useTable({columns, data})
  // Render Data Table UI
  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.map((row, i) => {
          prepareRow(row);
          return (
            <tr {...row.getRowProps()}>
              {row
                .cells
                .map(cell => {
                  return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
                })}
            </tr>
          )
        })}
      </tbody>
    </table>
  )
}
function App() {
  const data = [
    {
      name: 'Leanne Graham',
      email: '[email protected]',
      age: 28,
      status: 'Active'
    },
    {
      name: 'Ervin Howell',
      email: '[email protected]',
      age: 35,
      status: 'Active'
    },
    {
      name: 'Clementine Bauch',
      email: '[email protected]',
      age: 33,
      status: 'Inactive'
    },
    {
      name: 'Patricia Lebsack',
      email: '[email protected]',
      age: 25,
      status: 'Active'
    },
    {
      name: 'Kamren',
      email: '[email protected]',
      age: 42,
      status: 'Active'
    },
    {
      name: 'Dennis Schulist',
      email: '[email protected]',
      age: 34,
      status: 'Inactive'
    },
    {
      name: 'Kurtis Weissnat',
      email: '[email protected]',
      age: 44,
      status: 'Active'
    },
    {
      name: 'Maxime_Nienow',
      email: '[email protected]',
      age: 26,
      status: 'Active'
    },
    {
      name: 'Glenna Reichert',
      email: '[email protected]',
      age: 30,
      status: 'Inactive'
    },                                
  ]
  const columns = [
    {
      Header: 'Name',
      accessor: 'name'
    }, {
      Header: 'Email',
      accessor: 'email'
    }, {
      Header: 'Age',
      accessor: 'age'
    }, {
      Header: 'Status',
      accessor: 'status'
    }
  ]
  return (
    <Styles>
      <Table
        data={data}
        columns={columns}
      />
    </Styles>
  )
}
export default App

React Table Pagination Example

Tables allow you to gather a large amount of information and display that data in a more organized way. The react-table package is highly scalable and responsive, and It offers you pagination feature to manage the significant amount of data efficiently.

You can manage the large amount of data with usePagination API. Place the following code in the src/App.js file to enable the pagination in React table.

React Table pagination needs to have usePagination imported along with useTable API. We implemented the default pagination in React Table that is highly customizable; you can edit and update the Pagination values even the initial Table page index.

Create Responsive Table in React

Now, we are going to learn how to create React Responsive Table using useFlexLayout API, the react-table plugin offers useFlexLayout API and It allows making full-width resizable data table that works flawlessly in every device.

Here is the code for full-width responsive data table example in React:

import React from 'react';
import styled from 'styled-components'
import { useTable, usePagination } from 'react-table'
const Styles = styled.div `
  table {
    width: 100%;
    border-spacing: 0;
    border: 1px solid black;
    tr {
      :last-child {
        td {
          border-bottom: 0;
        }
      }
    }
    th,
    td {
      margin: 0;
      padding: 1rem;
      border-bottom: 1px solid black;
      border-right: 1px solid black;
      :last-child {
        border-right: 0;
      }
    }
  }
`
function Table({columns, data}) {
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    prepareRow,
    page, // Instead of using 'rows', we'll use page,
    // which has only the rows for the active page
    // The rest of these things are super handy, too ;)
    canPreviousPage,
    canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    setPageSize,
    state: { pageIndex, pageSize },
  } = useTable(
    {
      columns,
      data,
      initialState: { pageIndex: 0 },
    },
    usePagination
  )
  // Render Data Table UI
  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()}>
          {page.map((row, i) => {
            prepareRow(row)
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map(cell => {
                  return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
                })}
              </tr>
            )
          })}
        </tbody>
      </table>  
     {/* Pagination */}
     <div className="pagination">
        <button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
          {'<<'}
        </button>{' '}
        <button onClick={() => previousPage()} disabled={!canPreviousPage}>
          {'<'}
        </button>{' '}
        <button onClick={() => nextPage()} disabled={!canNextPage}>
          {'>'}
        </button>{' '}
        <button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
          {'>>'}
        </button>{' '}
        <span>
          Page{' '}
          <strong>
            {pageIndex + 1} of {pageOptions.length}
          </strong>{' '}
        </span>
        <span>
          | Go to page:{' '}
          <input
            type="number"
            defaultValue={pageIndex + 1}
            onChange={e => {
              const page = e.target.value ? Number(e.target.value) - 1 : 0
              gotoPage(page)
            }}
            style={{ width: '100px' }}
          />
        </span>{' '}
        <select
          value={pageSize}
          onChange={e => {
            setPageSize(Number(e.target.value))
          }}
        >
          {[3, 7, 15].map(pageSize => (
            <option key={pageSize} value={pageSize}>
              Show {pageSize}
            </option>
          ))}
        </select>
      </div>
    </>
  )
}
function App() {
  const data = [
    {
      name: 'Leanne Graham',
      email: '[email protected]',
      age: 28,
      status: 'Active'
    },
    {
      name: 'Ervin Howell',
      email: '[email protected]',
      age: 35,
      status: 'Active'
    },
    {
      name: 'Clementine Bauch',
      email: '[email protected]',
      age: 33,
      status: 'Inactive'
    },
    {
      name: 'Patricia Lebsack',
      email: '[email protected]',
      age: 25,
      status: 'Active'
    },
    {
      name: 'Kamren',
      email: '[email protected]',
      age: 42,
      status: 'Active'
    },
    {
      name: 'Dennis Schulist',
      email: '[email protected]',
      age: 34,
      status: 'Inactive'
    },
    {
      name: 'Kurtis Weissnat',
      email: '[email protected]',
      age: 44,
      status: 'Active'
    },
    {
      name: 'Maxime_Nienow',
      email: '[email protected]',
      age: 26,
      status: 'Active'
    },
    {
      name: 'Glenna Reichert',
      email: '[email protected]',
      age: 30,
      status: 'Inactive'
    },                                
  ]
  const columns = [
    {
      Header: 'Name',
      accessor: 'name'
    }, {
      Header: 'Email',
      accessor: 'email'
    }, {
      Header: 'Age',
      accessor: 'age'
    }, {
      Header: 'Status',
      accessor: 'status'
    }
  ]
  return (
    <Styles>
      <Table data={data} columns={columns}/>
    </Styles>
  )
}
export default App

Create Responsive Table in React

Now, we are going to learn how to create React Responsive Table using useFlexLayout API, the react-table plugin offers useFlexLayout API and It allows making full-width resizable data table that works flawlessly in every device.

Here is the code for full-width responsive data table example in React:

import React from 'react'
import styled from 'styled-components'
import {
  useTable,
  useResizeColumns,
  useFlexLayout,
  useRowSelect,
} from 'react-table'
const Styles = styled.div`
  padding: 1rem;
  .table {
    ${''}
    display: block;
    ${''}
    overflow: auto;
    border-spacing: 0;
    border: 1px solid black;
    .thead {
      ${''}
      overflow-y: auto;
      overflow-x: hidden;
    }
    .tbody {
      ${''}
      overflow-y: scroll;
      overflow-x: hidden;
      height: 250px;
    }
    .tr {
      :last-child {
        .td {
          border-bottom: 0;
        }
      }
      border-bottom: 1px solid black;
    }
    .th,
    .td {
      margin: 0;
      padding: 0.5rem;
      border-right: 1px solid black;
      ${''}
      position: relative;
      :last-child {
        border-right: 0;
      }
      .resizer {
        right: -5px;
        background: blue;
        width: 10px;
        height: 100%;
        position: absolute;
        top: 0;
        z-index: 1;
        ${''}
        touch-action:none;
        &.isResizing {
          background: red;
        }
      }
    }
    .th {
      &:last-of-type {
        .resizer {
          ${''}
          ${''}
          right: -15px;
        }
      }
    }
  }
`
const headerProps = (props, { column }) => getStyles(props, column.align)
const cellProps = (props, { cell }) => getStyles(props, cell.column.align)
const getStyles = (props, align = 'left') => [
  props,
  {
    style: {
      justifyContent: align === 'right' ? 'flex-end' : 'flex-start',
      alignItems: 'flex-start',
      display: 'flex',
    },
  },
]
function Table({ columns, data }) {
  const defaultColumn = React.useMemo(
    () => ({
      minWidth: 30,
      width: 150,
      maxWidth: 200,
    }),
    []
  )
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
  } = useTable(
    {
      columns,
      data,
      defaultColumn,
    },
    useResizeColumns,
    useFlexLayout,
    useRowSelect,
    hooks => {
    }
  )
  return (
    <div {...getTableProps()} className="table">
      <div>
        {headerGroups.map(headerGroup => (
          <div
            {...headerGroup.getHeaderGroupProps({
              style: { paddingRight: '15px' },
            })}
            className="tr"
          >
            {headerGroup.headers.map(column => (
              <div {...column.getHeaderProps(headerProps)} className="th">
                {column.render('Header')}
                {column.canResize && (
                  <div
                    {...column.getResizerProps()}
                    className={`resizer ${
                      column.isResizing ? 'isResizing' : ''
                    }`}
                  />
                )}
              </div>
            ))}
          </div>
        ))}
      </div>
      <div {...getTableBodyProps()} className="tbody">
        {rows.map((row, i) => {
          prepareRow(row)
          return (
            <div {...row.getRowProps()} className="tr">
              {row.cells.map(cell => {
                return (
                  <div {...cell.getCellProps(cellProps)} className="td">
                    {cell.render('Cell')}
                  </div>
                )
              })}
            </div>
          )
        })}
      </div>
    </div>
  )
}
function App() {
  const data = [
    {
      name: 'Leanne Graham',
      email: '[email protected]',
      age: 28,
      status: 'Active'
    },
    {
      name: 'Ervin Howell',
      email: '[email protected]',
      age: 35,
      status: 'Active'
    },
    {
      name: 'Clementine Bauch',
      email: '[email protected]',
      age: 33,
      status: 'Inactive'
    },
    {
      name: 'Patricia Lebsack',
      email: '[email protected]',
      age: 25,
      status: 'Active'
    },
    {
      name: 'Kamren',
      email: '[email protected]',
      age: 42,
      status: 'Active'
    },
    {
      name: 'Dennis Schulist',
      email: '[email protected]',
      age: 34,
      status: 'Inactive'
    },
    {
      name: 'Kurtis Weissnat',
      email: '[email protected]',
      age: 44,
      status: 'Active'
    }                            
  ]
  const columns = [
    {
      Header: 'Name',
      accessor: 'name'
    }, {
      Header: 'Email',
      accessor: 'email'
    }, {
      Header: 'Age',
      accessor: 'age'
    }, {
      Header: 'Status',
      accessor: 'status'
    }
  ]
  return (
    <Styles>
      <Table columns={columns} data={data} />
    </Styles>
  )
}
export default App

Create React Data Table Sorting

Sorting is a way of arranging the data in ascending or descending order, and It helps to sort the large amount of data (numbers and words) in Table.

We are going to implement the Table sorting functionality in React app using the react-table’ useSortBy API package.

Here is the final code for React data table sorting feature:

import React from 'react'
import styled from 'styled-components'
import { useTable, useSortBy } from 'react-table'
const Styles = styled.div`
  padding: 1rem;
  table {
    border-spacing: 0;
    border: 1px solid black;
    tr {
      :last-child {
        td {
          border-bottom: 0;
        }
      }
    }
    th,
    td {
      margin: 0;
      padding: 0.5rem;
      border-bottom: 1px solid black;
      border-right: 1px solid black;
      :last-child {
        border-right: 0;
      }
    }
  }
`
function Table({ columns, data }) {
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
  } = useTable(
    {
      columns,
      data,
    },
    useSortBy
  )
  // We don't want to render all 2000 rows for this example, so cap
  // it at 20 for this use case
  const firstPageRows = rows.slice(0, 20)
  return (
    <>
      <table {...getTableProps()}>
        <thead>
          {headerGroups.map(headerGroup => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map(column => (
                // Add the sorting props to control sorting. For this example
                // we can add them into the header props
                <th {...column.getHeaderProps(column.getSortByToggleProps())}>
                  {column.render('Header')}
                  {/* Add a sort direction indicator */}
                  <span>
                    {column.isSorted
                      ? column.isSortedDesc
                        ? ' 🔽'
                        : ' 🔼'
                      : ''}
                  </span>
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {firstPageRows.map(
            (row, i) => {
              prepareRow(row);
              return (
                <tr {...row.getRowProps()}>
                  {row.cells.map(cell => {
                    return (
                      <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
                    )
                  })}
                </tr>
              )}
          )}
        </tbody>
      </table>
    </>
  )
}
function App() {
  const data = [
    {
      name: 'Leanne Graham',
      email: '[email protected]',
      age: 28,
      status: 'Active'
    },
    {
      name: 'Ervin Howell',
      email: '[email protected]',
      age: 35,
      status: 'Active'
    },
    {
      name: 'Clementine Bauch',
      email: '[email protected]',
      age: 33,
      status: 'Inactive'
    },
    {
      name: 'Patricia Lebsack',
      email: '[email protected]',
      age: 25,
      status: 'Active'
    },
    {
      name: 'Kamren',
      email: '[email protected]',
      age: 42,
      status: 'Active'
    },
    {
      name: 'Dennis Schulist',
      email: '[email protected]',
      age: 34,
      status: 'Inactive'
    },
    {
      name: 'Kurtis Weissnat',
      email: '[email protected]',
      age: 44,
      status: 'Active'
    },
    {
      name: 'Maxime_Nienow',
      email: '[email protected]',
      age: 26,
      status: 'Active'
    },
    {
      name: 'Glenna Reichert',
      email: '[email protected]',
      age: 30,
      status: 'Inactive'
    },                                
  ]
  const columns = [
    {
      Header: 'Name',
      accessor: 'name'
    }, {
      Header: 'Email',
      accessor: 'email'
    }, {
      Header: 'Age',
      accessor: 'age'
    }, {
      Header: 'Status',
      accessor: 'status'
    }
  ]
  return (
    <Styles>
      <Table columns={columns} data={data} />
    </Styles>
  )
}
export default App

i hope you like this articlle.

Author : Harsukh Makwana
Harsukh Makwana

Hi, My name is Harsukh Makwana. i have been work with many programming language like php, python, javascript, node, react, anguler, etc.. since last 5 year. if you have any issue or want me hire then contact me on [email protected]