Back to home

Table Components Example

Demonstrates the full table system in src/common/components/table: DataTable, headers, cells, pagination and empty state.

Full-featured DataTable

Search, batch operations, row selection, sorting, filtering, column visibility, editable cells and pagination — all in one table.

ID
Name
Email
Status
Gender
Amount
CurrencyAgeActiveRemarkSortCreatedActions
1
Alice
alice@example.com
Enable
$1,280.50
USD
28
2023-11-15 06:13:20
2
Bob
bob@example.com
Enable
€640.00
EUR
35
2023-11-15 06:13:22
3
Carol
carol@example.com
Disable
$3,200.00
USD
42
2023-11-15 06:13:24
4
David
david@example.com
Enable
CN¥900.00
CNY
31
2023-11-15 06:13:26
5
Eve
eve@example.com
Disable
¥1,560
JPY
26
2023-11-15 06:13:28

Tree table

Hierarchical rows with expand/collapse using TreeCell.

NameEmail
Amount
Status
Engineering
Engineering
eng@example.com
$5,000.00
Enable
Marketing
Marketing
mkt@example.com
€1,500.00
Enable

Pagination primitives

Standalone Pagination / PaginationContent / PaginationItem / PaginationLink building blocks.

Empty state

EmptyRow shows a placeholder when there are no rows.

NameEmailStatus
No results.

Table Components (components/table) Usage Guide

Overview

src/common/components/table/ is a table system built on @tanstack/react-table + shadcn/ui. The core is DataTable, working with headers (header/), cells (cell/) and pagination (pagination/pager).

DataTable enables via useReactTable: sorting, filtering, column visibility, row selection, expanding (tree) and manual pagination (manualPagination: true — you slice the page yourself, recordTotal is the total count).

DataTable — the core table

import {DataTable} from "@/common/components/table/data-table";

<DataTable<T>
  columns={columns}
  result={result}
  setData={setResult}
  tableName="UserExample"
  primary="id"
  i18n={true}
  initHandler={init}
  deleteHandler={deleteHandler}
  EditComponent={EditPage}
  RowOperationComponents={[]}
  SearchComponent={Search}
  OperationComponent={Operation}
  defaultPager={{pageIndex: 0, pageSize: 10}}
/>
PropTypeRequiredDescription
columnsColumnDef<T,string>[]YesColumn definitions
resultResultYesData source; result.data = { list, recordTotal, dictionary }
setDataDispatch<SetStateAction<Result>>YessetState used to update result
initHandler() => voidYesReload (reset to page 1); called after row edit/delete
primarystringNoPrimary-key field name (used by deleteHandler)
tableNamestringNoi18n namespace; headers translate via useTranslations(tableName)
i18nbooleanNoTranslate headers (t.has(column.id)) and cell dictionaries (KVS.<field>.<value>)
hiddenColumnsVisibilityStateNoInitially hidden columns
SearchComponentComponentType<TableOperationProps>NoSearch bar; must assign meta.searchHandler
OperationComponentComponentType<TableOperationProps>NoToolbar (batch actions)
EditComponentComponentType<CellContextProps>NoRow edit dialog content (wrapped in a Dialog by PopItem)
deleteHandler(id) => voidNoRow delete callback
RowOperationComponentsComponentType<CellContextProps>[]NoExtra custom row actions in the action menu
parent{}NoArbitrary context (the demo passes a controller via parent)
defaultPagerPaginationStateNoDefault pagination

Because manualPagination is true, result.data.list must already be the current page; sorting/filtering stay client-side over the current page.

Cells (cell/)

Each cell factory returns a render component that you assign to a column's cell.

  • NormalCell(field, width?, handler?) — plain text; maps through result.data.dictionary[field] and translates via KVS.<field>.<value> when i18n is on.
  • CheckBoxCell — row selection; pair with CheckboxHeader; get selected ids via TableUtils.getSelectedIds(table).
  • CurrencyCell(field, currencyField) — formats the amount with Intl.NumberFormat using the currency field.
  • InputCell(field, type, width?) — inline edit; type="checkbox" renders a checkbox, otherwise an <Input>; writes back to row.original[field].
  • SelectCell(field, i18n?, readOnly?) — inline select from result.data.dictionary[field]; readOnly renders text only.
  • SortableCell(field) — number input; on blur it re-sorts the current page by sort and calls setData.
  • UnixTimestampCell(field, category?) — formats via dayjs to YYYY-MM-DD HH:mm:ss.
  • TreeCell(field) — expand/collapse button + indent, showing field; data must provide subRows.
  • OperationCell (internal) — triggered when a column's cell is the string "Actions": edit (EditComponent dialog), delete (deleteHandler), custom row actions (RowOperationComponents).

Headers (header/)

  • PlainTextHeader({columnTitle}) — plain text header; i18n overrides with t(column.id).
  • NormalHeader({showFilter, showSort, columnTitle}) — wraps ColumnOperation to add sort + filter.
  • CheckboxHeader — select-all / indeterminate.
  • ColumnFilter() — column visibility dropdown listing columns where getCanHide() is true.
  • EmptyHeader — blank header (used for the tree expander column).

Others

  • ColumnOperation({columnTitle, showFilter, showSort, column}) — sort/filter controls inside a header.
  • Pager({table}) — pagination bar for DataTable; calls meta.searchHandler on page change.
  • Pagination family — standalone pagination atoms (Pagination/PaginationContent/PaginationItem/PaginationLink/PaginationPrevious/PaginationNext/PaginationFirst/PaginationLast/PaginationEllipsis).
  • EmptyRow({columnSize}) — no-data placeholder, rendered automatically by DataTable.
  • CellRenderer — cell dispatcher (internal); routes cell === "Actions" to OperationCell, otherwise flexRender.