Widgets
Table
Renders tabular data with column definitions, optional sorting, and row selection.
Renders tabular data with column definitions, optional sorting, and row selection.
Usage
import { rgb, ui } from "@rezi-ui/core";
ui.table({
id: "users",
columns: [
{ key: "name", header: "Name", flex: 1, sortable: true, overflow: "middle" },
{ key: "role", header: "Role", width: 12 },
],
data: state.users,
getRowKey: (u) => u.id,
selection: state.selection,
selectionMode: "multi",
onSelectionChange: (keys) => app.update((s) => ({ ...s, selection: keys })),
stripeStyle: { odd: rgb(34, 37, 45) },
borderStyle: { variant: "double", color: rgb(120, 130, 145) },
})Boilerplate-free: useTable
Use useTable(ctx, ...) inside composite widgets to auto-manage selection, sorting, and wiring:
import { defineWidget, ui, useTable } from "@rezi-ui/core";
const FilesTable = defineWidget\<{ rows: readonly { id: string; name: string; size: number }[] }>(
(props, ctx) => {
const table = useTable(ctx, {
id: "files",
rows: props.rows,
columns: [
{ key: "name", header: "Name", flex: 1 },
{ key: "size", header: "Size", width: 10, align: "right" },
],
selectable: "multi",
sortable: true,
});
return ui.table(table.props);
},
);useTable returns:
props: ready forui.table(...)selection,clearSelectionsortColumn,sortDirection,setSortrows: sorted rows currently rendered byprops
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | required | Unique identifier for focus and events |
columns | TableColumn[] | required | Column definitions (key, header, width/flex, sortability, renderers, overflow) |
data | T[] | required | Row data |
getRowKey | (row: T, index: number) => string | required | Stable key for each row |
rowHeight | number | 1 | Row height in cells. Use positive values for predictable keyboard and mouse navigation. |
headerHeight | number | 1 | Header row height in cells when showHeader is true. |
selection | string[] | [] | Currently selected row keys |
selectionMode | "none" | "single" | "multi" | "none" | Selection behavior |
onSelectionChange | (keys: string[]) => void | - | Called when selection changes |
sortColumn | string | - | Currently sorted column key |
sortDirection | "asc" | "desc" | - | Current sort direction |
onSort | (column: string, direction: "asc" | "desc") => void | - | Called when sort changes |
onRowPress | (row: T, index: number) => void | - | Row activation callback |
onRowDoublePress | (row: T, index: number) => void | - | Row double-activation callback (double-click) |
virtualized | boolean | true | Enable windowed rendering for large datasets |
overscan | number | 3 | Extra rows rendered outside viewport |
showHeader | boolean | true | Show/hide header row |
stripedRows | boolean | false | Legacy stripe toggle (kept for compatibility) |
stripeStyle | { odd?, even? } | - | Stripe background colors. Providing this enables stripes even when stripedRows is false. |
border | "none" | "single" | "single" | Legacy border toggle (kept for compatibility) |
borderStyle | { variant?, color? } | - | Border glyph variant (single, double, rounded, heavy, dashed, heavy-dashed) and optional border color |
focusConfig | FocusConfig | - | Control focus visuals; { indicator: "none" } suppresses focused row highlight |
dsSize | "sm" | "md" | "lg" | "md" | Design-system size preset for table recipe spacing |
dsTone | "default" | "primary" | "danger" | "success" | "warning" | "default" | Design-system tone hook for recipe variants |
Design System Styling
Tables are design-system styled by default under the active ThemeDefinition.
tableRecipe() provides consistent colors for:
import { recipe } from "@rezi-ui/core";
// recipe.table(colors, { state: "header" | "row" | "selectedRow" | "focusedRow" | "stripe" })This covers header, body rows, selected rows, focused rows, and stripe rows. See the Design System specification for details.
Examples
Sortable table
ui.table({
id: "files",
columns: [
{ key: "name", header: "Name", flex: 1, sortable: true },
{ key: "size", header: "Size", width: 10, align: "right", sortable: true },
],
data: files,
getRowKey: (f) => f.path,
sortColumn: state.sortColumn,
sortDirection: state.sortDirection,
onSort: (column, direction) => app.update((s) => ({ ...s, sortColumn: column, sortDirection: direction })),
})Behavior
- Arrow keys navigate rows. Enter activates the selected row.
- Mouse click on a row selects it and moves focus to the table.
- In
selectionMode: "multi", Ctrl-click toggles the clicked row and Shift-click extends from the last clicked row. - Mouse click on a sortable header toggles sort and fires
onSort(column, direction). - When focused: Up from the first row focuses the header. Left/Right moves between columns. Enter toggles sort on the focused header.
- Double click on a row fires
onRowDoublePress(when provided). - Mouse scroll wheel scrolls rows when the table is virtualized.
Notes
- Tables can be virtualized; prefer virtualization for large datasets.
- Selection is tracked by row keys. Provide a stable
getRowKey. headerHeightis ignored whenshowHeaderisfalse.- Column
overflowdefaults to"ellipsis"and supports"clip"and"middle"per column. - Tables render a single-line frame by default. Set
border: "none"to suppress it, and useborderStyleto customize the active frame variant or color.
Related
- Virtual List - Windowed rendering for large linear datasets
- Tree - Hierarchical data navigation
- Input and Focus - Keyboard navigation behavior