Introduction: Why React Tables Matter
In almost every data-driven application—be it a dashboard, CRM, or admin panel—tables are critical for displaying structured information. But building efficient, responsive, and feature-rich tables from scratch can be time-consuming.
React offers multiple ways to build tables:
-
Plain JSX tables (good for simple use-cases)
-
React Table library (perfect for complex features like sorting, filtering, and pagination)
✅ Problem Solved: Tables built with React enable dynamic rendering, improve maintainability, and scale easily with large data sets.
Rendering a Basic Table Using JSX
Let’s begin by building a simple static table using plain JSX.
✅ Step 1: Sample Data
const users = [
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' },
{ id: 3, name: 'Charlie', email: '[email protected]' }
];
✅ Step 2: JSX Table Component
function BasicTable() {
return (
<table border="1" cellPadding="10">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{users.map(user => (
<tr key={user.id}>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.email}</td>
</tr>
))}
</tbody>
</table>
);
}
⚙️ Building Advanced Tables Using react-table
For advanced use-cases like sorting, filtering, pagination, and custom cell rendering, the react-table
library is highly recommended.
✅ Step 1: Install react-table
npm install react-table
✅ Step 2: Define Columns and Data
import { useTable } from 'react-table';
const data = [
{ id: 1, name: 'Alice', role: 'Admin' },
{ id: 2, name: 'Bob', role: 'Editor' },
{ id: 3, name: 'Charlie', role: 'Viewer' }
];
const columns = [
{
Header: 'ID',
accessor: 'id' // accessor is the "key" in the data
},
{
Header: 'Name',
accessor: 'name'
},
{
Header: 'Role',
accessor: 'role'
}
];
✅ Step 3: Create a Table Using useTable
function ReactTableComponent() {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
useTable({ columns, data });
return (
<table {...getTableProps()} border="1" cellPadding="10">
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(col => (
<th {...col.getHeaderProps()}>{col.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>
);
}
✅ Full Working Example with react-table
import React from 'react';
import { useTable } from 'react-table';
const TableComponent = () => {
const data = React.useMemo(
() => [
{ id: 1, name: 'Alice', role: 'Admin' },
{ id: 2, name: 'Bob', role: 'Editor' },
{ id: 3, name: 'Charlie', role: 'Viewer' }
],
[]
);
const columns = React.useMemo(
() => [
{ Header: 'ID', accessor: 'id' },
{ Header: 'Name', accessor: 'name' },
{ Header: 'Role', accessor: 'role' }
],
[]
);
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
useTable({ columns, data });
return (
<table {...getTableProps()} style={{ border: '1px solid #ccc', width: '100%' }}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()} style={{ backgroundColor: '#f5f5f5' }}>
{headerGroup.headers.map(col => (
<th {...col.getHeaderProps()} style={{ padding: 10 }}>{col.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => (
<td {...cell.getCellProps()} style={{ padding: 10 }}>{cell.render('Cell')}</td>
))}
</tr>
);
})}
</tbody>
</table>
);
};
export default TableComponent;
Feature Comparison: JSX vs React Table
Feature | JSX Table | react-table |
---|---|---|
Dynamic rendering | ✅ Yes | ✅ Yes |
Sorting | ❌ Manual | ✅ Built-in |
Filtering | ❌ Manual | ✅ Built-in |
Pagination | ❌ Manual | ✅ Add-on support |
Custom cell rendering | ✅ With effort | ✅ Easier & flexible |
Lightweight | ✅ Yes | ⚠️ Medium-sized bundle |
⚠️ Tips & Common Pitfalls
✅ Tips
-
Use
React.memo
for rows in large tables. -
For API data, fetch and set it with
useEffect()
+useState()
. -
Use
react-table
plugins for additional features (e.g., pagination, global filter).
❌ Common Pitfalls
Mistake | Problem | Solution |
---|---|---|
Missing key in list elements |
React warning, re-render issues | Always use a unique identifier |
Large data tables in JSX | Performance degradation | Use virtualization (e.g., react-virtual) |
Forgetting to memoize data/columns | Unnecessary re-renders | Use React.useMemo() |
Copy/paste Bootstrap classes | May conflict with table layout | Use inline styles or utility classes |
Conclusion: Choose the Right Table Strategy in React
React gives you flexibility—use simple JSX for basic tables, and react-table for robust, scalable features.
Best Practices:
Keep data and columns separate and reusable.
Use memoization for performance.
Avoid manually building sort/filter logic—use libraries when complexity grows.