A read-only data table that displays rows fetched from an integration gateway endpoint (asyncData: true) or populated from the form model via expressions/populates (dataType: "STATIC").
Read Form Rules before using this component — keys, labels, required fields, expressions, visibility, and validation all follow shared conventions.
endpointCode)customgenericdatafetch + populates) for read-only displayInstead of customdatatable, use… |
For… |
|---|---|
customdatasettable |
Data already in the form model (set via expressions) or a direct non-gateway URL fetch; or when row click selection is needed |
customitemselectiontable |
Picking items row-by-row with explicit Add/Remove action buttons and a paired selected-items table |
customeditabletable |
Inline-editable grids where each cell is a typed input (text, number, date, select) |
customdropdowndatafetchpaginated |
Picking a single value from a large paginated integration-driven list |
| Prop | Type | Required? | Description |
|---|---|---|---|
columns |
array |
required | Column definitions — each entry: { "key": "fieldInRow", "title": "Display Label" } |
dataType |
"STATIC" | "DYNAMIC" |
optional | "STATIC" uses props.items (set via expression); "DYNAMIC" is unused for async fetches (use asyncData instead). |
items |
array |
optional | Row data array; set via expressions when dataType is "STATIC". Never hardcode. |
asyncData |
boolean |
optional | If true, fetches rows from dataset on component init; default false. |
dataset |
object |
required when asyncData: true |
API fetch configuration (see below). |
selectable |
boolean |
optional | Allow row selection; set false for pure display. Default true. |
isSelectable |
boolean |
optional | Alternative selection flag used alongside selectable; set false for read-only. |
minSelection |
number |
optional | Minimum rows that must be selected. |
maxSelection |
number |
optional | Maximum selectable rows. |
searchable |
boolean |
optional | Show search input; default true. |
isSearchVisible |
boolean |
optional | Alternative visibility flag for the search input. |
searchPlaceHolder |
string |
optional | Placeholder text for the search box; default "Search". |
searchKeywordKey |
string |
conditional | API request param key for the search term (required when searching with asyncData: true). |
isSortVisible |
boolean |
optional | Show sort controls. |
sortKey |
string |
optional | API param key for the sort column. |
sortDirectionKey |
string |
optional | API param key for sort direction; if omitted, direction is appended to sortKey. |
paginationVisible |
boolean |
optional | Show pagination controls. |
pageSize |
number |
optional | Rows per page; default 10. |
pageSizeOptions |
array |
optional | Available page size choices; default [10, 50, 100]. |
pageSizeKey |
string |
optional | Key name for page size in API request params. |
currentPageKey |
string |
optional | Key name for current page number in API request params. |
zeroBasedPageIndex |
boolean |
optional | If true, page index sent to API starts at 0; default false. |
emptyMessage |
string |
optional | Message when no rows exist; default "No Records". |
noDataMessage |
string |
optional | Alternative empty-state message key (mirrors emptyMessage). |
title |
string |
optional | Table heading rendered above the table. |
customTableClass |
string |
optional | Extra CSS class applied to the table element. |
minimalPagination |
boolean |
optional | Show simplified pagination controls; default false. |
hideFromPreview |
boolean |
optional | Exclude from the application preview/summary page. |
dataset object (when asyncData: true)| Field | Type | Required? | Description |
|---|---|---|---|
url |
string |
required | API endpoint URL (usually /integration/v1/fetch/sync). |
endpointCode |
string |
conditional | Gateway endpoint code; triggers integration fetch sync POST. |
dataField |
string |
optional | Dot-notation path to the rows array in the API response. |
httpMethod |
"POST" | "GET" |
optional | HTTP method; defaults to GET when omitted. |
useBaseUrl |
boolean |
optional | Prepend API gateway base URL to dataset.url. |
params |
object |
optional | Additional query/body params sent with every request. |
headers |
object |
optional | Custom HTTP headers. |
collectionSizeKey |
string |
optional | Dot-notation path to total record count in response (for server-side pagination). |
The most common pattern: rows populated by an upstream lookup (expressions/populates) and displayed read-only.
{
"key": "PREVIOUS_FOUNDERS",
"type": "customdatatable",
"props": {
"label": "Previous Shareholders",
"dataType": "STATIC",
"selectable": false,
"isSelectable": false,
"searchable": false,
"isSearchVisible": false,
"isSortVisible": false,
"paginationVisible": false,
"noDataMessage": "No shareholders found",
"columns": [
{ "key": "firstName", "title": "First Name" },
{ "key": "lastName", "title": "Last Name" }
]
},
"expressions": {
"props.items": "model?.FETCHED_SHAREHOLDERS"
}
}
Server-paginated fetch from the integration gateway with searching, sorting, and zero-based pagination.
{
"key": "PROPERTY_HISTORY",
"type": "customdatatable",
"props": {
"label": "Property Transaction History",
"selectable": false,
"isSelectable": false,
"searchable": true,
"isSearchVisible": true,
"searchPlaceHolder": "Search transactions",
"searchKeywordKey": "keyword",
"isSortVisible": true,
"paginationVisible": true,
"asyncData": true,
"dataset": {
"url": "/integration/v1/fetch/sync",
"useBaseUrl": true,
"endpointCode": "GET_PROPERTY_TRANSACTIONS",
"dataField": "data.transactions",
"httpMethod": "POST",
"params": {
"propertyType": "RESIDENTIAL"
},
"collectionSizeKey": "data.totalElements"
},
"columns": [
{ "key": "transactionDate", "title": "Date" },
{ "key": "description", "title": "Description" },
{ "key": "amount", "title": "Amount (RWF)" },
{ "key": "status", "title": "Status" }
],
"pageSize": 10,
"pageSizeOptions": [10, 50, 100],
"pageSizeKey": "size",
"currentPageKey": "page",
"zeroBasedPageIndex": true,
"sortKey": "sort",
"sortDirectionKey": "direction",
"emptyMessage": "No transaction history found",
"title": "Transaction History",
"hideFromPreview": true
}
}
{ "field": "...", "header": "..." } for column definitions — the correct format is { "key": "...", "title": "..." }.asyncData: true but omitting dataset — the component skips the fetch and renders an empty table.selectable: false and isSelectable: false on a display-only table — the default for selectable is true, making rows clickable when that is not intended.searchable: true with asyncData: true but omitting searchKeywordKey — the search box appears but the API receives no keyword param.zeroBasedPageIndex: false (or omitting it) when the API expects 0-based pages — the first page of results is skipped.collectionSizeKey directly on props instead of inside props.dataset — the total count is never read.props.items as a static array in the config instead of via expressions — items must be populated at runtime from the model.key is UPPER_SNAKE_CASE and unique across the entire formprops.label is present, unique, and correctly casedcolumns use the { "key": "...", "title": "..." } shapeselectable: false and isSelectable: falseasyncData: true is paired with a complete dataset block (url, endpointCode, dataField)searchable: true with asyncData: true includes searchKeywordKeyprops.items is set via expressions, never hardcodedzeroBasedPageIndex matches what the API expectscollectionSizeKey lives inside dataset, not on the root propscustomdatatable when row selection or direct non-gateway URLs are needed (see "When NOT to use")