Components

customdatatable

A read-only data table that displays rows fetched from an integration gateway endpoint or populated from the form model via expressions.

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.

When to use

  • Displaying tabular results from an integration gateway endpoint on form init (e.g. transaction history, parcel records, shareholder lists fetched via endpointCode)
  • Rendering rows already populated into the form model by an upstream lookup (customgenericdatafetch + populates) for read-only display
  • Showing server-paginated, searchable, sortable tables where row click selection is not required

When NOT to use

Instead of customdatatable, use…For…
customdatasettableData already in the form model (set via expressions) or a direct non-gateway URL fetch; or when row click selection is needed
customitemselectiontablePicking items row-by-row with explicit Add/Remove action buttons and a paired selected-items table
customeditabletableInline-editable grids where each cell is a typed input (text, number, date, select)
customdropdowndatafetchpaginatedPicking a single value from a large paginated integration-driven list

Props

PropTypeRequired?Description
columnsarrayrequiredColumn 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).
itemsarrayoptionalRow data array; set via expressions when dataType is "STATIC". Never hardcode.
asyncDatabooleanoptionalIf true, fetches rows from dataset on component init; default false.
datasetobjectrequired when asyncData: trueAPI fetch configuration (see below).
selectablebooleanoptionalAllow row selection; set false for pure display. Default true.
isSelectablebooleanoptionalAlternative selection flag used alongside selectable; set false for read-only.
minSelectionnumberoptionalMinimum rows that must be selected.
maxSelectionnumberoptionalMaximum selectable rows.
searchablebooleanoptionalShow search input; default true.
isSearchVisiblebooleanoptionalAlternative visibility flag for the search input.
searchPlaceHolderstringoptionalPlaceholder text for the search box; default "Search".
searchKeywordKeystringconditionalAPI request param key for the search term (required when searching with asyncData: true).
isSortVisiblebooleanoptionalShow sort controls.
sortKeystringoptionalAPI param key for the sort column.
sortDirectionKeystringoptionalAPI param key for sort direction; if omitted, direction is appended to sortKey.
paginationVisiblebooleanoptionalShow pagination controls.
pageSizenumberoptionalRows per page; default 10.
pageSizeOptionsarrayoptionalAvailable page size choices; default [10, 50, 100].
pageSizeKeystringoptionalKey name for page size in API request params.
currentPageKeystringoptionalKey name for current page number in API request params.
zeroBasedPageIndexbooleanoptionalIf true, page index sent to API starts at 0; default false.
emptyMessagestringoptionalMessage when no rows exist; default "No Records".
noDataMessagestringoptionalAlternative empty-state message key (mirrors emptyMessage).
titlestringoptionalTable heading rendered above the table.
customTableClassstringoptionalExtra CSS class applied to the table element.
minimalPaginationbooleanoptionalShow simplified pagination controls; default false.
hideFromPreviewbooleanoptionalExclude from the application preview/summary page.

dataset object (when asyncData: true)

FieldTypeRequired?Description
urlstringrequiredAPI endpoint URL (usually /integration/v1/fetch/sync).
endpointCodestringconditionalGateway endpoint code; triggers integration fetch sync POST.
dataFieldstringoptionalDot-notation path to the rows array in the API response.
httpMethod"POST" | "GET"optionalHTTP method; defaults to GET when omitted.
useBaseUrlbooleanoptionalPrepend API gateway base URL to dataset.url.
paramsobjectoptionalAdditional query/body params sent with every request.
headersobjectoptionalCustom HTTP headers.
collectionSizeKeystringoptionalDot-notation path to total record count in response (for server-side pagination).

Examples

Static rows from the form model

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
  }
}

Common mistakes

  • Using { "field": "...", "header": "..." } for column definitions — the correct format is { "key": "...", "title": "..." }.
  • Setting asyncData: true but omitting dataset — the component skips the fetch and renders an empty table.
  • Omitting both selectable: false and isSelectable: false on a display-only table — the default for selectable is true, making rows clickable when that is not intended.
  • Setting searchable: true with asyncData: true but omitting searchKeywordKey — the search box appears but the API receives no keyword param.
  • Using zeroBasedPageIndex: false (or omitting it) when the API expects 0-based pages — the first page of results is skipped.
  • Putting collectionSizeKey directly on props instead of inside props.dataset — the total count is never read.
  • Setting props.items as a static array in the config instead of via expressionsitems must be populated at runtime from the model.

Checklist

  • key is UPPER_SNAKE_CASE and unique across the entire form
  • props.label is present, unique, and correctly cased
  • columns use the { "key": "...", "title": "..." } shape
  • Display-only tables set both selectable: false and isSelectable: false
  • asyncData: true is paired with a complete dataset block (url, endpointCode, dataField)
  • searchable: true with asyncData: true includes searchKeywordKey
  • props.items is set via expressions, never hardcoded
  • zeroBasedPageIndex matches what the API expects
  • collectionSizeKey lives inside dataset, not on the root props
  • Not using customdatatable when row selection or direct non-gateway URLs are needed (see "When NOT to use")

On this page