React Table is a versatile and efficient library to build tables in React applications.
The library offers developers a quick way to display, sort, filter, and paginate large data sets in a consistent, organized table design.
One of the best features of React Table is that one can customize the table in multiple ways to suit any need or fit the design of the application.
It is possible to create fast tables with basic data or complex data grids with a variety of additional functions . Such task can be easily implemented using a React Table .
React Table uses hooks to help you build tables, giving you complete control over how you want the table to look and work (this is called Headless UI).
These dedicated hooks are lightweight, fast and flexible but they don't come with any in built markup or styles.
This philosophy aligns closely with the broader use of hooks in the React ecosystem, including React Native hooks leveraged to build interactive components for mobile apps.
Many big tech companies like Google, Apple, and Microsoft use React Table because it's flexible and easy to use.
Features like sorting, pagination, and filtering are all done with hooks, making it simple to add these functions to your tables.
Before you start using React Table, make sure you have the following:
React Table comes with a variety of powerful features that make it easy to create flexible and customizable tables.
You can customize the headers, rows, and cells to fit your needs. This allows you to control what data is displayed and how it looks.
Opt for the most suitable react based CMS to implement customised components and elements catering to your content management system.
import { useTable } from 'react-table';
const columns = [
{
Header: 'Name',
accessor: 'name', // accessor is the "key" in the data
},
{
Header: 'Age',
accessor: 'age',
},
];
const data = [
{ name: 'John Doe', age: 28 },
{ name: 'Jane Smith', age: 34 },
];
function TableComponent() {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ columns, data });
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 => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
))}
</tr>
);
})}
</tbody>
</table>
);
}
output:
You can sort the table by multiple columns, making it easier to organize and find data.
import React from 'react';
import { useTable, useSortBy } from 'react-table';
const TableComponent = ({ columns, data }) => {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable(
{
columns,
data
},
useSortBy
);
return (
<div className="overflow-x-auto">
<table {...getTableProps()} className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th
{...column.getHeaderProps(column.getSortByToggleProps())}
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
<div className="flex items-center">
{column.render('Header')}
<span className="ml-2">
{column.isSorted ? (
column.isSortedDesc ? (
<svg className="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 12a.5.5 0 01-.4-.2l-5-5a.5.5 0 11.8-.6L10 10.8l4.6-4.6a.5.5 0 11.8.6l-5 5a.5.5 0 01-.4.2z" clipRule="evenodd" />
</svg>
) : (
<svg className="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 8a.5.5 0 01.4.2l5 5a.5.5 0 11-.8.6L10 9.2 5.4 14a.5.5 0 11-.8-.6l5-5a.5.5 0 01.4-.2z" clipRule="evenodd" />
</svg>
)
) : (
<svg className="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 8a.5.5 0 01.4.2l5 5a.5.5 0 11-.8.6L10 9.2 5.4 14a.5.5 0 11-.8-.6l5-5a.5.5 0 01.4-.2zM10 12a.5.5 0 01-.4-.2l-5-5a.5.5 0 11.8-.6L10 10.8l4.6-4.6a.5.5 0 11.8.6l-5 5a.5.5 0 01-.4.2z" clipRule="evenodd" />
</svg>
)}
</span>
</div>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()} className="bg-white divide-y divide-gray-200">
{rows.map(row => {
prepareRow(row);
return (
<tr {...row.getRowProps()} className="hover:bg-gray-100">
{row.cells.map(cell => (
<td {...cell.getCellProps()} className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{cell.render('Cell')}
</td>
))}
</tr>
);
})}
</tbody>
</table>
</div>
);
};
export default TableComponent;
Output:
You can filter the data in the table using built-in or custom filters.
import { useTable, useFilters } from 'react-table';
// Custom filter UI for a column
function DefaultColumnFilter({
column: { filterValue, preFilteredRows, setFilter },
}) {
const count = preFilteredRows.length;
return (
<input
value={filterValue || ''}
onChange={e => {
setFilter(e.target.value || undefined); // Set undefined to remove the filter entirely
}}
placeholder={`Search ${count} records...`}
/>
);
}
function TableComponent() {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable(
{ columns, data, defaultColumn: { Filter: DefaultColumnFilter } },
useFilters
);
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>
{column.render('Header')}
<div>{column.canFilter ? column.render('Filter') : null}</div>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
))}
</tr>
);
})}
</tbody>
</table>
);
}
Pagination helps manage large datasets by splitting them into smaller, more manageable pages.
import { useTable, usePagination } from 'react-table';
function TableComponent() {
const { getTableProps, getTableBodyProps, headerGroups, page, prepareRow, canPreviousPage, canNextPage, pageOptions, nextPage, previousPage, state: { pageIndex } } = useTable(
{ columns, data, initialState: { pageIndex: 0 } },
usePagination
);
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 => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
))}
</tr>
);
})}
</tbody>
</table>
<div>
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
Previous
</button>
<span>
Page{' '}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>
</span>
<button onClick={() => nextPage()} disabled={!canNextPage}>
Next
</button>
</div>
</>
);
}
Inline editing allows users to edit table data directly within the table.
import { useState } from 'react';
import { useTable } from 'react-table';
function EditableCell({ value: initialValue, row: { index }, column: { id }, updateMyData }) {
const [value, setValue] = useState(initialValue);
const onChange = e => {
setValue(e.target.value);
};
const onBlur = () => {
updateMyData(index, id, value);
};
return <input value={value} onChange={onChange} onBlur={onBlur} />;
}
const defaultColumn = {
Cell: EditableCell,
};
function TableComponent({ columns, data, updateMyData }) {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable(
{ columns, data, defaultColumn, updateMyData }
);
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 => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
))}
</tr>
);
})}
</tbody>
</table>
);
}
You can add checkboxes for row selection, making it easier to manage selected rows.
import { useTable, useRowSelect } from 'react-table';
// Add a checkbox to each row
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 TableComponent() {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow, selectedFlatRows } = 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.map(row => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
))}
</tr>
);
})}
</tbody>
</table>
);
}
You can resize and reorder columns to suit your needs.
import { useTable, useResizeColumns, useFlexLayout } from 'react-table';
function TableComponent() {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable(
{ columns, data },
useResizeColumns,
useFlexLayout
);
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()} style={{ minWidth: column.minWidth, width: column.width }}>
{column.render('Header')}
<div {...column.getResizerProps()} className="resizer" />
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
))}
</tr>
);
})}
</tbody>
</table>
);
}
React Table is optimized for handling large datasets efficiently, making it suitable for applications with extensive data.
Its virtualized rendering, pagination, and sorting features ensure smooth performance, even with complex data sets.
This is particularly crucial for applications that rely on real-time data processing, analytics dashboards, or backend systems that interact heavily with RESTful web services.
There are resources (platforms)to asess RESTful web services and their working capabilities
You can easily style React Table using CSS-in-JS libraries like styled-components or any other CSS method.
import styled from 'styled-components';
const Styles = styled.div`
table {
width: 100%;
border-spacing: 0;
border: 1px solid black;
th,
td {
margin: 0;
padding: 0.5rem;
border-bottom: 1px solid black;
border-right: 1px solid black;
:last-child {
border-right: 0;
}
}
th {
background: lightgray;
}
}
`;
function TableComponent() {
return (
<Styles>
<table>
{/* Table content */}
</table>
</Styles>
);
}
In this article, we learned how to build a table interface using React. Creating a basic table is not too hard, but try to avoid redoing things that have already been done whenever possible. I hope you found learning about table interfaces enjoyable.