DataTable
Easy to use table and datagrids built using TanStack Table .
#
Documentation
#
#
Install
#
Install the required peer dependencies to start using this component:
npm install @tanstack/react-table
#
Usage
#
Use the table
prop to pass a table instance returned from useReactTable()
hook. At minimum make sure to include columns
, data
, and getCoreRowModel
when using the hook.
First Name | Last Name | Status | Amount |
---|---|---|---|
Arthur | Morgan | success | $20 |
John | Marston | processing | $12.75 |
Micah | Bell | failed | $1.25 |
App.tsx
import { DataTable, DataTableBody } from "@optiaxiom/react/unstable";
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import { columns } from "./columns";
import { data } from "./data";
export function App() {
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
});
return (
<DataTable table={table}>
<DataTableBody />
</DataTable>
);
}
#
Anatomy
#
import { DataTable, DataTableBody, DataTableFooter } from "@optiaxiom/react";
export default () => (
<DataTable>
<DataTableBody />
<DataTableFooter />
</DataTable>
);
#
Vertical scrolling
#
Headers in DataTable
are sticky by default. Set a height on the component to allow scrolling vertically when a large number of rows are present.
ID | First Name | Last Name | Amount |
---|
App.tsx
import { DataTable, DataTableBody } from "@optiaxiom/react/unstable";
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import { columns } from "./columns";
import { data } from "./data";
export function App() {
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
state: { pagination: { pageIndex: 0, pageSize: data.length } },
});
return (
<DataTable maxH="xs" table={table}>
<DataTableBody />
</DataTable>
);
}
#
Column pinning
#
Follow the column pinning guide and use the columnPinning
option to pin columns either to the left or right side of the table.
ID | Username | Email | First Name | Last Name | Job Title | Amount |
---|
App.tsx
import { DataTable, DataTableBody } from "@optiaxiom/react/unstable";
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import { columns } from "./columns";
import { data } from "./data";
export function App() {
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
state: {
columnPinning: {
left: ["id", "username"],
},
pagination: { pageIndex: 0, pageSize: data.length },
},
});
return (
<DataTable maxH="xs" table={table}>
<DataTableBody />
</DataTable>
);
}
#
Row selection
#
Follow the row selection guide to allow selecting and highlighting rows.
ID | First Name | Last Name | Amount | |
---|---|---|---|---|
1 | Edgardo | Lubowitz | $696.47 | |
2 | Henri | Paucek-Kshlerin | $719.47 | |
3 | Everardo | Kessler | $392.12 | |
4 | Granville | Deckow | $59.67 | |
5 | Justyn | Nicolas | $175.45 |
App.tsx
import { DataTable, DataTableBody } from "@optiaxiom/react/unstable";
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import { columns } from "./columns";
import { data } from "./data";
export function App() {
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
});
return (
<DataTable table={table}>
<DataTableBody />
</DataTable>
);
}
#
Row actions
#
Use the TableActions
component to show dropdown menus within rows that are only visible when the user hovers over the row or navigates to the menu using keyboards.
Hover over the rows to perform more actions:
First Name | Last Name | Amount | |
---|---|---|---|
Edgardo | Lubowitz | $696.47 | |
Henri | Paucek-Kshlerin | $719.47 | |
Everardo | Kessler | $392.12 | |
Granville | Deckow | $59.67 | |
Justyn | Nicolas | $175.45 |
App.tsx
import { DataTable, DataTableBody } from "@optiaxiom/react/unstable";
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import { columns } from "./columns";
import { data } from "./data";
export function App() {
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
});
return (
<DataTable table={table}>
<DataTableBody />
</DataTable>
);
}
#
Pagination
#
DataTable
supports both client-side and server-side pagination. Follow the pagination guide to learn how to implement pagination with TanStack Table.
#
Client side
#
Simply provide the getPaginationRowModel
and pagination
options to use client-side pagination.
ID | First Name | Last Name | Amount |
---|---|---|---|
1 | Edgardo | Lubowitz | $696.47 |
2 | Henri | Paucek-Kshlerin | $719.47 |
3 | Everardo | Kessler | $392.12 |
4 | Granville | Deckow | $59.67 |
5 | Justyn | Nicolas | $175.45 |
6 | Modesta | Reichert | $849.44 |
7 | Francesca | Greenholt | $322.96 |
8 | Audreanne | Keeling | $630.98 |
9 | Herminio | Kautzer | $493.69 |
10 | Tyreek | Muller | $893.39 |
1 - 10 of 50
App.tsx
import {
DataTable,
DataTableBody,
DataTableFooter,
} from "@optiaxiom/react/unstable";
import {
getCoreRowModel,
getPaginationRowModel,
useReactTable,
} from "@tanstack/react-table";
import { columns } from "./columns";
import { data } from "./data";
export function App() {
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
initialState: { pagination: { pageIndex: 0, pageSize: 10 } },
});
return (
<DataTable maxH="xs" table={table}>
<DataTableBody />
<DataTableFooter />
</DataTable>
);
}
#
Server side
#
To implement manual server-side pagination we can use manualPagination
and rowCount
. Then combine it with onPaginationChange
and state.pagination
to control pagination and react to changes.
ID | First Name | Last Name | Amount |
---|---|---|---|
1 | Edgardo | Lubowitz | $696.47 |
2 | Henri | Paucek-Kshlerin | $719.47 |
3 | Everardo | Kessler | $392.12 |
4 | Granville | Deckow | $59.67 |
5 | Justyn | Nicolas | $175.45 |
6 | Modesta | Reichert | $849.44 |
7 | Francesca | Greenholt | $322.96 |
8 | Audreanne | Keeling | $630.98 |
9 | Herminio | Kautzer | $493.69 |
10 | Tyreek | Muller | $893.39 |
1 - 10 of 50
App.tsx
import {
DataTable,
DataTableBody,
DataTableFooter,
} from "@optiaxiom/react/unstable";
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import { useMemo, useState } from "react";
import { columns } from "./columns";
import { data } from "./data";
/**
* Simulate fetching data from server.
*/
const fetchData = ({ pageIndex = 0, pageSize = 10 }) =>
data.slice(pageIndex * pageSize, (pageIndex + 1) * pageSize);
export function App() {
const [pagination, setPagination] = useState({
pageIndex: 0,
pageSize: 10,
});
const table = useReactTable({
columns,
data: useMemo(() => fetchData(pagination), [pagination]),
getCoreRowModel: getCoreRowModel(),
manualPagination: true,
onPaginationChange: setPagination,
rowCount: data.length,
state: { pagination },
});
return (
<DataTable maxH="xs" table={table}>
<DataTableBody />
<DataTableFooter />
</DataTable>
);
}
#
Loading state
#
Set the loading
prop to true
to show a loading skeleton while your table data is loading.
ID | First Name | Last Name | Amount |
---|---|---|---|
App.tsx
import { Flex, Switch } from "@optiaxiom/react";
import { DataTable, DataTableBody } from "@optiaxiom/react/unstable";
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import { useState } from "react";
import { columns } from "./columns";
export function App() {
const [data] = useState([]);
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
});
const [loading, setLoading] = useState(true);
return (
<Flex alignItems="start" maxW="full">
<Switch checked={loading} onCheckedChange={setLoading}>
Loading
</Switch>
<DataTable maxH="xs" table={table}>
<DataTableBody loading={loading} />
</DataTable>
</Flex>
);
}
#
Sorting
#
DataTable
supports both client-side and server-side sorting. Follow the sorting guide to learn how to implement sorting with TanStack Table.
#
Client side
#
Simply provide getSortedRowModel
on table and enableSorting
on each column you’d like to be sortable to use client-side sorting.
Hover over and click the table headers to sort by columns:
ID | |||
---|---|---|---|
1 | Edgardo | Lubowitz | $696.47 |
2 | Henri | Paucek-Kshlerin | $719.47 |
3 | Everardo | Kessler | $392.12 |
4 | Granville | Deckow | $59.67 |
5 | Justyn | Nicolas | $175.45 |
6 | Modesta | Reichert | $849.44 |
7 | Francesca | Greenholt | $322.96 |
8 | Audreanne | Keeling | $630.98 |
9 | Herminio | Kautzer | $493.69 |
10 | Tyreek | Muller | $893.39 |
App.tsx
import { DataTable, DataTableBody } from "@optiaxiom/react/unstable";
import {
getCoreRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { columns } from "./columns";
import { data } from "./data";
export function App() {
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
});
return (
<DataTable maxH="xs" table={table}>
<DataTableBody />
</DataTable>
);
}
#
Server side
#
To implement manual server-side sorting we can use manualSorting
and enableSorting
. Then combine it with onSortingChange
and state.sorting
to control sorting and react to changes.
Hover over and click the table headers to sort by columns:
ID | |||
---|---|---|---|
8 | Audreanne | Keeling | $630.98 |
1 | Edgardo | Lubowitz | $696.47 |
3 | Everardo | Kessler | $392.12 |
7 | Francesca | Greenholt | $322.96 |
4 | Granville | Deckow | $59.67 |
2 | Henri | Paucek-Kshlerin | $719.47 |
9 | Herminio | Kautzer | $493.69 |
5 | Justyn | Nicolas | $175.45 |
6 | Modesta | Reichert | $849.44 |
10 | Tyreek | Muller | $893.39 |
App.tsx
import { DataTable, DataTableBody } from "@optiaxiom/react/unstable";
import {
getCoreRowModel,
type SortingState,
useReactTable,
} from "@tanstack/react-table";
import { useMemo, useState } from "react";
import { columns } from "./columns";
import { data } from "./data";
export function App() {
const [sorting, setSorting] = useState([
{
desc: false,
id: "firstName",
},
]);
const table = useReactTable({
columns,
data: useMemo(() => sortData(sorting), [sorting]),
getCoreRowModel: getCoreRowModel(),
onSortingChange: setSorting,
state: { sorting },
});
return (
<DataTable maxH="xs" table={table}>
<DataTableBody />
</DataTable>
);
}
/**
* Simulate sorting data from server.
*/
const sortData = (sorting: SortingState) =>
data.toSorted((a, b) => {
for (const state of sorting) {
if (
!(
state.id === "amount" ||
state.id === "firstName" ||
state.id === "lastName"
)
) {
return 0;
}
const result =
(state.desc ? -1 : 1) *
a[state.id].localeCompare(b[state.id], undefined, { numeric: true });
if (result !== 0) {
return result;
}
}
return 0;
});
#
Virtualized
#
Table automatically uses virtualized rendering when rows and columns cross a certain threshold to improve rendering performance.
Columns will be virtualized when there are more than 20 columns in a table and rows will be virtualized when there are more than 20 rows rendered or if columns are also being virtualized.
Timer: 0s (to simulate re-rendering)
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | Column 7 | Column 8 | Column 9 | Column 10 | Column 11 | Column 12 | Column 13 | Column 14 | Column 15 | Column 16 | Column 17 | Column 18 | Column 19 | Column 20 | Column 21 | Column 22 | Column 23 | Column 24 | Column 25 | Column 26 | Column 27 | Column 28 | Column 29 | Column 30 | Column 31 | Column 32 | Column 33 | Column 34 | Column 35 | Column 36 | Column 37 | Column 38 | Column 39 | Column 40 | Column 41 | Column 42 | Column 43 | Column 44 | Column 45 | Column 46 | Column 47 | Column 48 | Column 49 | Column 50 |
---|
App.tsx
import { faker } from "@faker-js/faker";
import { Flex, Text } from "@optiaxiom/react";
import { DataTable, DataTableBody } from "@optiaxiom/react/unstable";
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import { useInViewTimer } from "./useInViewTimer";
faker.seed(123);
const cols = 50;
const rows = 500;
const data = Array.from({ length: rows }, () =>
Object.fromEntries(
Array.from({ length: cols }, (_, index) => [
`col${index}`,
faker.book.title(),
]),
),
);
const columns = Array.from({ length: cols }, (_, index) => ({
accessorKey: `col${index}`,
header: `Column ${index + 1}`,
}));
export function App() {
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
state: { pagination: { pageIndex: 0, pageSize: data.length } },
});
/**
* A simple hook to re-render the table when it is visible on the screen.
*/
const [count, ref] = useInViewTimer();
return (
<Flex maxW="full" ref={ref}>
<Text>Timer: {count}s (to simulate re-rendering)</Text>
<DataTable maxH="sm" table={table}>
<DataTableBody />
</DataTable>
</Flex>
);
}
#
Props
#
#
DataTable
#
Supports all Box props in addition to its own. Renders a <div>
element.
Prop |
---|
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
table* Pass the table instance returned from
|
#
DataTableBody
#
Supports all Box props in addition to its own. Renders a <div>
element.
Prop |
---|
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
estimatedRowHeight The estimated height of rows in pixels when virtualization is enabled.
Default: |
loading Indicates if the table is loading
|
#
DataTableFooter
#
Supports all Box props in addition to its own. Renders a <div>
element.
Prop |
---|
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
pageSizeOptions
Default: |
showPageSizeOptions
|
#
TableActions
#
Supports all Box props in addition to its own. Renders a <div>
element.
Prop |
---|
asChild Change the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
#
Changelog
#
#
0.3.0
#
- Added component