DataTable
A data table driven by column definitions with sorting, global search, pagination and row selection, plus loading skeletons and an empty state. Every layer is controllable or uncontrolled.
Installation
pnpm dlx @elyri/cli@latest add data-tableExamples
Basic
Pass columns and data; accessor picks the value, cell customizes a cell.
import { DataTable } from './components/elyri/DataTable';
import type { DataTableColumn } from './components/elyri/DataTable';
interface Member {
id: number;
name: string;
role: string;
status: string;
seats: number;
}
const members = [
{ id: 1, name: 'Ada Lovelace', role: 'admin', status: 'active', seats: 3 },
{ id: 2, name: 'Alan Turing', role: 'editor', status: 'active', seats: 2 },
{ id: 3, name: 'Grace Hopper', role: 'admin', status: 'paused', seats: 5 },
];
const columns: DataTableColumn<Member>[] = [
{ id: 'name', header: 'Member', accessor: 'name', sortable: true },
{ id: 'role', header: 'Role', accessor: 'role' },
{ id: 'status', header: 'Status', accessor: 'status', align: 'center' },
{ id: 'seats', header: 'Seats', accessor: 'seats', sortable: true, align: 'right' },
];
export function Example() {
return <DataTable caption="Workspace members" columns={columns} data={members} />;
}Sorting
Mark a column sortable to cycle asc / desc / none on header click, with aria-sort kept in sync.
import { DataTable } from './components/elyri/DataTable';
export function Example() {
return (
<DataTable
columns={columns}
data={members}
defaultSort={{ columnId: 'seats', direction: 'desc' }}
/>
);
}Global search
Enable searchable to show a box that filters every searchable column, case-insensitively.
import { DataTable } from './components/elyri/DataTable';
export function Example() {
return <DataTable searchable title="Members" columns={columns} data={members} />;
}Row selection
Enable selectable for a selection column; the header selects the page with an indeterminate state.
import { DataTable } from './components/elyri/DataTable';
export function Example() {
return (
<DataTable
selectable
columns={columns}
data={members}
defaultSelectedKeys={['1']}
pageSizeOptions={[3, 6]}
defaultPageSize={3}
/>
);
}Pagination
Turn on pagination with pageSize and pageSizeOptions; controlled or uncontrolled.
import { DataTable } from './components/elyri/DataTable';
export function Example() {
return (
<DataTable columns={columns} data={members} pageSize={3} pageSizeOptions={[3, 6]} />
);
}Loading & empty
loading renders skeleton rows; with no data the built-in empty state shows, replaceable via empty.
import { DataTable } from './components/elyri/DataTable';
export function Example() {
return (
<>
<DataTable loading columns={columns} data={[]} loadingRows={3} />
<DataTable columns={columns} data={[]} />
</>
);
}Appearance
Combine variant / size / striped / hoverable / stickyHeader for different densities.
import { DataTable } from './components/elyri/DataTable';
export function Example() {
return (
<>
<DataTable size="sm" striped columns={columns} data={members} />
<DataTable variant="plain" hoverable columns={columns} data={members} />
</>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns | DataTableColumn<T>[] | — | Column definitions |
data | T[] | — | Row data |
getRowId | (row, index) => string | — | Row key; defaults to row.id, falling back to the original index |
title | ReactNode | — | Toolbar title |
caption | ReactNode | — | Table caption |
sort | DataTableSortState | null | — | Controlled sort state, null when unsorted |
defaultSort | DataTableSortState | null | — | Uncontrolled initial sort state |
onSortChange | (sort) => void | — | Sort change handler |
selectable | boolean | false | Show a selection column |
selectedKeys | string[] | — | Controlled selected row keys |
defaultSelectedKeys | string[] | — | Uncontrolled initial selected row keys |
onSelectionChange | (keys) => void | — | Selection change handler |
searchable | boolean | false | Show a global search box in the toolbar |
search | string | — | Controlled search query |
onSearchChange | (value) => void | — | Search change handler |
globalFilterFn | (row, query) => boolean | — | Custom global search matcher |
pagination | boolean | true | Enable pagination, defaults to true |
page | number | — | Controlled current page (1-based) |
onPageChange | (page) => void | — | Page change handler |
pageSize | number | 10 | Rows per page |
pageSizeOptions | number[] | — | Page size options; renders a selector when provided |
loading | boolean | false | Loading state, renders skeleton rows |
loadingRows | number | — | Skeleton row count, defaults to the current page size |
empty | ReactNode | — | Custom empty state |
variant | 'outline' | 'plain' | 'outline' | Appearance: 'outline' | 'plain' |
size | 'sm' | 'md' | 'lg' | 'md' | Padding and font size: 'sm' | 'md' | 'lg' |
striped | boolean | false | Zebra stripes |
hoverable | boolean | true | Highlight on hover, defaults to true |
stickyHeader | boolean | false | Sticky header (give the container a height or maxHeight) |
toolbar | ReactNode | — | Extra toolbar content on the right |
labels | Partial<DataTableLabels> | — | Override built-in labels (search, select-all, pagination, …) |
...rest | HTMLAttributes | — | Remaining props are forwarded to the native div |