Table
One table for activity, UTXOs and explorer data. Rows are virtualized against a fixed row height, amounts are always mono and right-aligned, and every async posture — first load, next page, empty, failed — has an explicit rendering.
Density
Comfortable 48px rows for wallet activity; dense 36px rows for the explorer. Headers are click-to-sort (live) — both ship sorted newest first via defaultSort.
12 fixture transactions: send/receive/swap × pending/confirming/confirmed/failed.
import { Table, type TableColumn } from "@coldharbor/ui";
import { transactions, type Transaction } from "@/fixtures";
const columns: TableColumn<Transaction>[] = [
{ key: "timestamp", header: "Age", sortable: true },
{ key: "amountDisplay", header: "Amount", align: "right",
cell: (tx) => <span className="font-mono tabular-nums">{tx.amountDisplay}</span> },
];
<Table
data={transactions}
columns={columns}
getRowId={(tx) => tx.id}
defaultSort={{ key: "timestamp", direction: "desc" }}
rowHeight={48}
height={340}
/>--ch-bg--ch-bg-raised--ch-surface-raised--ch-border--ch-fg--ch-fg-muted--ch-primary
Selection
selectable adds a leading checkbox column with select-all in the header; selected rows tint with the primary. Two rows ship pre-selected here. Row hover tint is a live pointer state — sweep the rows.
<Table selectable defaultSelectedRowIds={ids} onSelectionChange={setIds} … />--ch-bg--ch-bg-raised--ch-surface-raised--ch-border--ch-fg--ch-fg-muted--ch-primary
Async postures
First load shows a full-viewport skeleton; paging appends skeleton rows under real data; empty and error render through the emptyState slot. Table has no dedicated error prop — the failed-fetch message goes through emptyState, styled with the danger token.
| No transactions yet — receive your first coins to see them here. | ||||||
| Could not reach the node — check your connection and retry. | ||||||
<Table data={[]} loading … /> // initial skeleton
<Table data={rows} loading skeletonRows={3} … /> // paging skeleton
<Table data={[]} emptyState={<Empty />} … /> // empty
<Table data={[]} emptyState={<FetchError />} … /> // error posture--ch-bg--ch-bg-raised--ch-surface-raised--ch-border--ch-fg--ch-fg-muted--ch-primary
Resizable & reorderable headers (live)
Drag a header to reorder its column; drag the right edge of a header to resize. Both are opt-in flags.
<Table resizable reorderable minColumnWidth={64} … />--ch-bg--ch-bg-raised--ch-surface-raised--ch-border--ch-fg--ch-fg-muted--ch-primary
Themes
A compact activity table under all three layers.
--ch-bg--ch-bg-raised--ch-surface-raised--ch-border--ch-fg--ch-fg-muted--ch-primary