TableBlock
A payment records table with row selection, a per-row action menu and built-in pagination.
TableBlock has a fixed, payment-specific row shape rather than configurable columns —
the name is broader than the block. When you need arbitrary columns, use
SearchableTableBlock, or compose Table directly from
@raydenui/ui.
Import
import { TableBlock } from "@raydenui/ui/blocks";
import type { TableBlockRow } from "@raydenui/ui/blocks";Usage
Basic
Each row supplies the full set of fields the table renders.
const rows: TableBlockRow[] = [
{
id: "1",
name: "Ada Lovelace",
email: "ada@example.com",
initials: "AL",
amount: "$1,200.00",
paymentType: "Card",
date: "12 Jun 2023",
time: "10:24 AM",
status: "Paid",
statusColor: "success",
},
];
<TableBlock rows={rows} />;Every optional control needs its handler
The block does not render a control that has nowhere to go:
- The actions column renders only when
onRowActionis supplied. - Pagination renders only when
page,totalPagesandonPageChangeare supplied together.
<TableBlock rows={rows} onRowAction={(rowId) => openMenuFor(rowId)} />const [page, setPage] = useState(1);
<TableBlock rows={rows} page={page} totalPages={8} onPageChange={setPage} />;Selection
Selection is uncontrolled unless you pass selectedIds. onSelectionChange fires with the
full resulting selection on every user interaction, and also whenever reconciliation
drops ids.
<TableBlock rows={rows} onSelectionChange={(ids) => setBulkTargets(ids)} />Controlled selection is the only way to keep a selection across pages:
const [selectedIds, setSelectedIds] = useState<string[]>([]);
<TableBlock
rows={pageRows}
selectedIds={selectedIds}
onSelectionChange={setSelectedIds}
page={page}
totalPages={8}
onPageChange={setPage}
/>;Selection reconciliation contract
An uncontrolled selection covers only the rows the block is currently given. When
rows changes, any selected id that is no longer present is dropped permanently — it does
not come back if that row returns later.
- Deleting a row deselects it.
- Replacing rows with new ids clears the selection, so the header reports “none selected” rather than a stale “all selected” over unchecked rows.
- Paginating outside the block, where you hand over a different
rowsarray, drops the selections that left with it. From the block’s side that is indistinguishable from deletion. - Reconciliation is never silent. Dropping ids fires
onSelectionChangewith what remains, so a bulk action cannot run against a row that is already gone.
A controlled selection is never reconciled. The value you supply is authoritative, and ids outside the current page are preserved by the toggles rather than dropped.
Full and partial selection are derived from membership of the rows on screen, never from set
sizes, so one of two rows reports aria-checked="mixed" rather than fully checked.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
rows | TableBlockRow[] | — | Required. Table rows. |
selectedIds | string[] | — | Controlled selection. The only way to keep a selection across pages. |
onSelectionChange | (ids: string[]) => void | — | Fired with the full resulting selection, including on reconciliation. |
onRowAction | (rowId: string) => void | — | Row action handler. The actions column renders only when supplied. |
page | number | — | Current page, 1-indexed. Pagination needs all three props. |
totalPages | number | — | Total pages. Pagination needs all three props. |
onPageChange | (page: number) => void | — | Page change handler. Pagination needs all three props. |
className | string | — | Additional class names. |
TableBlockRow
| Field | Type | Description |
|---|---|---|
id | string | Unique row identifier. |
name | string | Person’s name. |
email | string | Shown under the name. |
initials | string | Avatar initials. |
amount | string | Pre-formatted amount. |
paymentType | string | Payment method label. |
date | string | Date label. |
time | string | Time label. |
status | string | Status label. |
statusColor | "success" | "warning" | "error" | "orange" | "blue" | "neutral" | Status badge colour. |
Every field except statusColor is required.
States
- default — the record table.
- partial selection — the select-all control reports
aria-checked="mixed". - no configured actions — the actions column and pagination are absent rather than inert.
Accessibility
- Selection checkboxes are named after their row, and the select-all control is named “Select all rows”.
- The row action button is named
Actions for <name>, using the row’s own name. - The action column has a visually hidden “Actions” heading, so the column is not empty for screen readers.
- The table has its own bounded horizontal scroll region, which is intentional for two-dimensional data rather than a reflow defect.
Known limitations
- The row shape is fixed and payment-specific. There is no column configuration.
- There is no loading, error or empty state. Render your own around the block.