Tabler React 2 Docs

Tables

Tables

Tables are used to display tabular data. They can be used to display data in a table, list, or any other tabular data.

Signature

import { Table } from "tabler-react-2";
<Table {...props} />;

Props

PropRequiredTypeDefaultDescription
columnsYesColumnAn array of column objects.
dataYesArrayAn array of data objects.

For all of the tables on this page, we will use this list of congress people. (click to expand)
[
{
"name": "Ed Case",
"email": "ed.case@mail.house.gov",
"party": "democrat",
"region": {
"state": "Hawaii",
"abbr": "HI",
"district": "1st"
},
"website": "https://case.house.gov"
},
{
"name": "Mike Carey",
"email": "mike.carey@mail.house.gov",
"party": "republican",
"region": {
"state": "Ohio",
"abbr": "OH",
"district": "15th"
},
"website": "https://carey.house.gov"
},
{
"name": "Andrew Clyde",
"email": "andrew.clyde@mail.house.gov",
"party": "republican",
"region": {
"state": "Georgia",
"abbr": "GA",
"district": "9th"
},
"website": "https://clyde.house.gov"
},
{
"name": "Angie Craig",
"email": "angie.craig@mail.house.gov",
"party": "democrat",
"region": {
"state": "Minnesota",
"abbr": "MN",
"district": "2nd"
},
"website": "https://craig.house.gov"
},
{
"name": "Rick Crawford",
"email": "rick.crawford@mail.house.gov",
"party": "republican",
"region": {
"state": "Arkansas",
"abbr": "AR",
"district": "1st"
},
"website": "https://crawford.house.gov"
},
{
"name": "Jared Golden",
"email": "jared.golden@mail.house.gov",
"party": "democrat",
"region": {
"state": "Maine",
"abbr": "ME",
"district": "2nd"
},
"website": "https://golden.house.gov"
},
{
"name": "Dusty Johnson",
"email": "dusty.johnson@mail.house.gov",
"party": "republican",
"region": {
"state": "South Dakota",
"abbr": "SD",
"district": "At-Large"
},
"website": "https://dustyjohnson.house.gov"
},
{
"name": "Susie Lee",
"email": "susie.lee@mail.house.gov",
"party": "democrat",
"region": {
"state": "Nevada",
"abbr": "NV",
"district": "3rd"
},
"website": "https://susielee.house.gov"
}
]

Basic Usage

The Table component is used to display tabular data. It takes an array of objects as a prop called columns. Each object in the array represents a column in the table. The object should have a label property that is the text to display in the column header, and a accessor property that is the key of the object to use for the data in that column.

The Table component also takes a data prop that is an array of objects. Each object in the array represents a row in the table. The object should have a key for each column in the columns array.

import congressPeople from "./congressPeople.json";
<Table
columns={[
{ label: "Name", accessor: "name", sortable: true },
{
label: "Party",
accessor: "party",
render: (party) => (
<>
<img src={`/${party}.png`} style={{ width: 25 }} /> {party}
</>
),
},
{
label: "State",
accessor: "region.state",
},
{
label: "District",
accessor: "region.district",
render: (district, row) => (
<>
<span className="text-secondary">{row.region.abbr}</span> {district}
</>
),
},
{
label: "Email",
accessor: "email",
className: "text-secondary",
render: (email) => (
<a href={`mailto:${email}`} className="text-reset">
<IconMail strokeWidth={1.5} />
</a>
),
},
]}
data={congressPeople}
/>;

Constructing the columns array

The columns prop is an array of objects. Each object represents a column in the table. It has the following properties:

PropRequiredTypeDefaultDescription
labelYesStringThe text to display in the column header.
accessorYesStringThe key of the object to use for the data in that column.
classNameNoStringAdditional CSS classes to apply to the column.
renderNoFunctionCustom render function for the cell content.
sortableNoBooleanfalseWhether the column is sortable.
sortFnNoFunctionCustom sorting function.

accessor

The accessor prop is the key of the object to use for the data in that column. It is a string that corresponds to the key of the object in the data array. It supports nested keys using dot notation.

Use the accessor prop to render simple text in your table. If you need any customization, use the render prop as well as accessor.

Setting the accessor prop to the string 'name' will return the values

<Table columns={[{ label: "Name", accessor: "name" }]} data={congressPeople} />

You can access the nested keys of (in this case) the region object by using dot notation. For example, setting the accessor prop to region.district will return the values

<Table
columns={[{ label: "District", accessor: "region.district" }]}
data={congressPeople}
/>

To access other keys in the object (combining multiple keys in a single cell), you cannot use the accessor. Still provide something to the accessor prop so there is not an error, but use the render prop to display the content.

render

The render prop is an optional function that will be called with the value of the cell and the row object.

It has the following signature:

render(value: any, row: object): React.ReactNode;

Where value is the value provided by the accessor and row is the entire row.

So, to render the congress person's party with the symbol, (assuming /democrat.png and /republican.png exist), you can use the render prop to display the party.

<Table
columns={[
{
label: "Person's Party",
accessor: "party",
render: (partyFromAccessor) => (
<>
<img src={`/${partyFromAccessor}.png`} style={{ width: 25 }} />
{partyFromAccessor}
</>
),
},
]}
data={congressPeople}
/>

To include other values from the row in the cell, you can use the second argument passed to the render function. In this case, we will leave the accessor the same, so the first argument will be either "democrat" or "republican". The second argument is the entire row object that we will pull the region.state value from.

<Table
columns={[
{
label: "Person's Party",
accessor: "party",
render: (party, row) => (
<>
{party} ({row.region.state})
</>
),
},
]}
data={congressPeople}
/>

sortable

The sortable prop is an optional boolean that determines whether the column is sortable. If it is set to true, the column will be sortable. The default value is false. It will sort based on the value of the column's accessor.

<Table
columns={[
{
label: "Name",
accessor: "name",
},
{
label: "Party",
accessor: "party",
render: ...,
sortable: true,
},
{
label: "State",
accessor: "region.state",
sortable: true,
},
]}
data={congressPeople}
/>

You can also pass a custom sorting function to the sortFn prop. The sorting function should take two arguments and return -1, 0, or 1. The first argument is the value of the first cell, and the second argument is the value of the second cell.

The default sorting function is

Default sorting function
const defaultSortFn = (a, b) => {
if (a === b) return 0;
return a > b ? 1 : -1;
};

If, for some reason, you wanted to sort by the length of the name, you could do the following:

const customSortFn = (a, b) => {
if (a.length === b.length) return 0;
return a.length > b.length ? 1 : -1;
};
<Table
columns={[
{
label: "Name",
accessor: "name",
sortFn: customSortFn,
sortable: true,
},
]}
data={congressPeople}
/>;

Note: Sorting only works for the data in the table. If, for example, you have thousands of rows and are only rendering a few, you will need to handle the sorting yourself, outside of the table. Incorporating internal pagination that supports sorting is a planned feature but not yet implemented.

External ordering

You can control ordering from the parent (e.g., server-side sort) and still use the table’s sortable headers. Provide the props below. When controlled, the table will not sort your data; it assumes you already passed rows in the desired order.

  • orderBy: accessor of the active column
  • order: either "asc" or "desc"
  • onSetOrder: called with (orderBy, order) when the user clicks a header
// Parent controls ordering and pagination
const [orderBy, setOrderBy] = useState('name');
const [order, setOrder] = useState('asc');
const [page, setPage] = useState(1);
const [size, setSize] = useState(10);
const ordered = [...allRows].sort((a, b) => {
const av = orderBy.split('.').reduce((acc, k) => acc?.[k], a);
const bv = orderBy.split('.').reduce((acc, k) => acc?.[k], b);
if (av === bv) return 0;
const cmp = av > bv ? 1 : -1;
return order === 'asc' ? cmp : -cmp;
});
const start = (page - 1) * size;
const currentData = ordered.slice(start, start + size);
<Table
columns={columns}
data={currentData}
showPagination
page={page}
size={size}
totalRows={allRows.length}
orderBy={orderBy}
order={order}
onSetOrder={(by, dir) => { setOrderBy(by); setOrder(dir); }}
onSetPage={setPage}
onSetSize={(n) => { setPage(1); setSize(n); }}
/>;

Pagination

The Table supports built-in pagination UI. Enable it with showPagination.

  • showPagination: toggles the pagination controls
  • defaultRowsPerPage: initial rows per page for internal mode
  • pageSizeOptions: selectable page sizes (default [10, 25, 50, 100])
<Table
columns={columns}
data={rows}
showPagination
defaultRowsPerPage={10}
pageSizeOptions={[10, 25, 50, 100]}
/>

External pagination

You can also fully control pagination from the parent (e.g., server-side paging) while keeping the same UI. Provide the controlled props and callbacks below. When any controlled pagination prop is provided, the table does not slice your data and instead assumes data already contains the current page.

  • page: current page (1-based)
  • size: current page size
  • totalRows: total available row count used for page count and the “Showing … of …” text
  • onSetPage: called with next page (1-based)
  • onSetSize: called with next page size

Aliases are supported for compatibility: rowsPerPage, onPageChange, onRowsPerPageChange.

// Parent controls the table
const [page, setPage] = useState(1);
const [rowsPerPage, setRowsPerPage] = useState(10);
const totalRows = allRows.length; // from your API
// Only pass the current slice to the table
const start = (page - 1) * rowsPerPage;
const currentData = allRows.slice(start, start + rowsPerPage);
<Table
columns={columns}
data={currentData}
showPagination
page={page}
size={rowsPerPage}
totalRows={totalRows}
onSetPage={setPage}
onSetSize={(n) => { setPage(1); setRowsPerPage(n); }}
/>;

If you don’t supply these controlled props, the table falls back to its internal pagination state, preserving backwards compatibility.

useTable hook

For async workflows, use the helper hook to centralize loading, pagination, count, and ordering while preserving the Table’s controlled API.

import { useEffect, useState } from 'react';
import { Table, useTable } from 'tabler-react-2';
function PeopleTable() {
const [rows, setRows] = useState([]);
const { tableProps, setLoading, setPage, setCount, setOrder } = useTable({
autoLoading: false,
onPageChange: async (page, size, sort) => {
setLoading(true);
try {
// fetch your data here using page, size, and sort
const res = await fetchPeople({ page, size, sort });
setRows(res.items);
setCount(res.total);
} finally {
setLoading(false);
}
},
onSortChange: async (by, dir) => {
// optionally kick off a fetch based on new sort
// setOrder(by, dir) is already called for you
},
});
useEffect(() => {
// initial load
setPage(1);
}, [setPage]);
return <Table {...tableProps} columns={[
{ label: 'Name', accessor: 'name', sortable: true },
{ label: 'Party', accessor: 'party', sortable: true },
{ label: 'State', accessor: 'region.state', sortable: true },
]} data={rows} />;
}

The hook returns:

  • tableProps: spread onto <Table /> to enable controlled pagination, ordering, and loading
  • setLoading, setPage, setCount: imperative helpers for async flows
  • Also available: page, size, count, orderBy, order, setSize, setOrder
Edit this page on GitHub