Table
A compound table and typed ERP data grid with paging, column controls, expansion, virtualization, editing, resizing, and reordering.
Installation
tsx
import { Table, type TableColumn, TableHead, TableBody, TableRow, TableHeaderCell, TableCell, TableBulkActions } from "madagent";Default
| Name | Role | Status | |
|---|---|---|---|
| Alice Johnson | alice@example.com | Admin | Active |
| Bob Smith | bob@example.com | Editor | Active |
| Carol Williams | carol@example.com | Viewer | Inactive |
| David Brown | david@example.com | Editor | Active |
| Eve Davis | eve@example.com | Admin | Active |
Striped
| Name | Role | |
|---|---|---|
| Alice Johnson | alice@example.com | Admin |
| Bob Smith | bob@example.com | Editor |
| Carol Williams | carol@example.com | Viewer |
| David Brown | david@example.com | Editor |
| Eve Davis | eve@example.com | Admin |
Compact Density
| Name | Role | |
|---|---|---|
| Alice Johnson | alice@example.com | Admin |
| Bob Smith | bob@example.com | Editor |
| Carol Williams | carol@example.com | Viewer |
| David Brown | david@example.com | Editor |
| Eve Davis | eve@example.com | Admin |
Tabular Numbers
| Item | Subtotal | Tax (14%) | Total |
|---|---|---|---|
| Annual subscription | E£18,000.00 | E£2,520.00 | E£20,520.00 |
| Setup fee | E£2,500.00 | E£350.00 | E£2,850.00 |
| Training workshop | E£4,800.00 | E£672.00 | E£5,472.00 |
| Priority support | E£7,200.00 | E£1,008.00 | E£8,208.00 |
Sortable Columns
| Status | |||
|---|---|---|---|
| Alice Johnson | alice@example.com | Admin | Active |
| Bob Smith | bob@example.com | Editor | Active |
| Carol Williams | carol@example.com | Viewer | Inactive |
| David Brown | david@example.com | Editor | Active |
| Eve Davis | eve@example.com | Admin | Active |
Bulk Actions
| Date | Team Member | Status | Amount | Expense Category | Receipt | |
|---|---|---|---|---|---|---|
| Feb 16 | Jane Black | Payment Pending | $50.25 | Travel - Vehicles | — | |
| Feb 16 | Jane Black | Pending Review | $16.75 | Travel - Vehicles | — | |
| Feb 14 | Jane Black | Declined | $35.00 | Travel - Flights | Uploaded | |
| Feb 14 | Mary Metcalfe | Details Requested | $480.50 | Travel - Flights | Uploaded | |
| Oct 1 | Fiona Laurice | Pending Review | $215.78 | Travel - Accommodation | — |
0 requests selected • $0.00 total
Typed data grid
| Expand | SKU⋮⋮ | Product⋮⋮ | On hand⋮⋮ | Warehouse⋮⋮ |
|---|---|---|---|---|
| SKU-0001 | Inventory item 1 | 20 | Cairo | |
| SKU-0002 | Inventory item 2 | 22 | Alexandria | |
| SKU-0003 | Inventory item 3 | 24 | Cairo | |
| SKU-0004 | Inventory item 4 | 26 | Alexandria | |
| SKU-0005 | Inventory item 5 | 28 | Cairo | |
| SKU-0006 | Inventory item 6 | 30 | Alexandria |
Virtualized rows
SKU | Product | On hand | Warehouse |
|---|---|---|---|
| SKU-0001 | Virtual inventory item 1 | 20 | Cairo |
| SKU-0002 | Virtual inventory item 2 | 22 | Alexandria |
| SKU-0003 | Virtual inventory item 3 | 24 | Cairo |
| SKU-0004 | Virtual inventory item 4 | 26 | Alexandria |
| SKU-0005 | Virtual inventory item 5 | 28 | Cairo |
| SKU-0006 | Virtual inventory item 6 | 30 | Alexandria |
| SKU-0007 | Virtual inventory item 7 | 32 | Cairo |
| SKU-0008 | Virtual inventory item 8 | 34 | Alexandria |
| SKU-0009 | Virtual inventory item 9 | 36 | Cairo |
| SKU-0010 | Virtual inventory item 10 | 38 | Alexandria |
| SKU-0011 | Virtual inventory item 11 | 40 | Cairo |
| SKU-0012 | Virtual inventory item 12 | 42 | Alexandria |
| SKU-0013 | Virtual inventory item 13 | 44 | Cairo |
| SKU-0014 | Virtual inventory item 14 | 46 | Alexandria |
| SKU-0015 | Virtual inventory item 15 | 48 | Cairo |
| SKU-0016 | Virtual inventory item 16 | 50 | Alexandria |
| SKU-0017 | Virtual inventory item 17 | 52 | Cairo |
| SKU-0018 | Virtual inventory item 18 | 54 | Alexandria |
| SKU-0019 | Virtual inventory item 19 | 56 | Cairo |
Loading and empty states
SKU | Product | On hand | Warehouse |
|---|---|---|---|
SKU | Product | On hand | Warehouse |
|---|---|---|---|
No inventory records Adjust filters or add the first item. | |||
Table Props
| Prop | Type | Default | Description |
|---|---|---|---|
striped | boolean | false | Alternating row background colors |
density | "compact""comfortable" | "comfortable" | Cell padding density |
stickyHeader | boolean | false | Sticky table header on scroll |
columns | TableColumn<TRow>[] | - | Enables the typed data-driven API while compound children remain supported |
rows | TRow[] | - | Records rendered by the typed data API |
getRowId | (row, index) => stringnumber | - | Stable row identity; defaults to row.id or the row index |
pagination | TablePaginationConfig | - | Page size, controlled/uncontrolled page state, server totals, and page-window options |
columnVisibility | Record<string, boolean> | - | Controlled column visibility map |
showColumnsMenu | boolean | true | Shows a Checkbox-backed visibility menu when columns are hideable |
onRowClick | (row, event) => void | - | Called when a data row is activated with the pointer |
expandableRows | boolean(row) => boolean | false | Enables logical row expansion controls |
renderExpanded | (row) => ReactNode | - | Renders the full-width expanded row panel |
loading | boolean | false | Replaces rows with semantic Skeleton rows and marks the table busy |
virtualized | { rowHeight; height?; overscan? } | - | Fixed-height row windowing for large datasets with focus restoration |
onCellEdit | (rowId, columnId, value, row) => void | - | Receives Enter-committed inline edits; Escape cancels |
resizableColumns | boolean | false | Enables pointer and keyboard resize handles for every column |
reorderableColumns | boolean | false | Enables drag reorder and logical Alt+Arrow keyboard reorder |
TableColumn
| Prop | Type | Default | Description |
|---|---|---|---|
id* | string | - | Stable column identifier |
header* | ReactNode | - | Header content |
accessor | keyof TRow(row) => unknown | - | Reads the raw cell value |
cell | (value, row, index) => ReactNode | - | Formats display content |
align | "start""center""end" | - | Logical text alignment |
width / minWidth / maxWidth | numberstring | - | Column sizing constraints; numeric sticky widths give deterministic offsets |
sticky | "start""end" | - | Pins the column to a logical table edge |
hideable | boolean | - | Adds the column to the visibility menu |
editable | boolean(row) => boolean | - | Starts an editor with Enter or double-click |
renderEditor | (editorProps) => ReactNode | - | Uses a custom madagent editor instead of the default text input |
resizable | boolean | - | Enables the column resize separator |
reorderable | boolean | - | Enables drag and Alt+Arrow reorder for this column |
HeaderCell Props
| Prop | Type | Default | Description |
|---|---|---|---|
sortable | boolean | false | Show sort controls |
sortDirection | "asc""desc""none" | "none" | Current sort direction |
onSort | (direction: SortDirection) => void | - | Called when a sort option is selected from the dropdown |
sortAscLabel | string | "Ascending" | Label for the ascending sort option |
sortDescLabel | string | "Descending" | Label for the descending sort option |
clearSortLabel | string | "Clear sort" | Label for the clear sort option |
BulkActions Props
| Prop | Type | Default | Description |
|---|---|---|---|
selectedRowIds | (string | number)[] | - | IDs currently selected in the table |
actions | TableBulkAction[] | - | Action buttons rendered inside the bulk action bar |
onAction | (actionId: string, selectedRowIds: (string | number)[]) => void | - | Called when any bulk action button is clicked |
onClearSelection | () => void | - | Optional callback to clear selected rows |
summary | ReactNode | - | Optional summary content (for example selected total amount) |
hideWhenEmpty | boolean | true | Hide the bulk actions bar when there are no selected rows |
RTL Support
Components automatically adapt to right-to-left languages using CSS logical properties.
Preview
| الاسم | البريد الإلكتروني | المبلغ | المسمى الوظيفي | |
|---|---|---|---|---|
| يوسف يعقوب | ahmed@example.com | 3842 | مصمم تطبيقات | |
| فاطمة علي | fatima@example.com | 1597 | مهندس صوت | |
| خالد حسن | khaled@example.com | 7260 | مدير التسويق |
2 عناصر محددة
Tabular Numbers
| البند | المبلغ | الضريبة (15%) | الإجمالي |
|---|---|---|---|
| اشتراك سنوي | 18,000.00 | 2,700.00 | 20,700.00 |
| رسوم التفعيل | 2,500.00 | 375.00 | 2,875.00 |
| ورشة تدريبية | 4,800.00 | 720.00 | 5,520.00 |
| دعم فني متقدم | 7,200.00 | 1,080.00 | 8,280.00 |
Usage
tsx
<Table>
<TableHead>
<TableRow>
<TableHeaderCell style={{ width: 52 }}>
<Checkbox aria-label="تحديد الكل" />
</TableHeaderCell>
<TableHeaderCell>الاسم</TableHeaderCell>
<TableHeaderCell>البريد الإلكتروني</TableHeaderCell>
<TableHeaderCell>المبلغ</TableHeaderCell>
<TableHeaderCell>الدور</TableHeaderCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell><Checkbox /></TableCell>
<TableCell>أحمد محمد</TableCell>
<TableCell>ahmed@example.com</TableCell>
<TableCell>3842</TableCell>
<TableCell>مشرف</TableCell>
</TableRow>
</TableBody>
</Table>
<TableBulkActions
selectedRowIds={selectedRowIds}
actions={[
{ id: "approve", label: "اعتماد", variant: "primary" },
{ id: "decline", label: "رفض", variant: "danger" },
]}
onClearSelection={() => setSelectedRowIds([])}
summary={`${selectedRowIds.length} عناصر محددة`}
/>