A tabular display that renders rows already in the form model (dataType: "STATIC") or fetched directly from a non-gateway URL (dataType: "DYNAMIC"). Optionally used as a selection input when isSelectable: true — the user picks a row and the value is written to the form control.
Read Form Rules before using this component — keys, labels, required fields, expressions, visibility, and validation all follow shared conventions.
expressions (e.g. STATIC mode with props.rows bound to model?.SOMETHING || [])dataType: "DYNAMIC")isSelectable: true)Instead of customdatasettable, use… |
For… |
|---|---|
customdatatable |
Async fetches that route through the integration gateway (endpointCode + /integration/...) |
customitemselectiontable |
Add/Remove row workflows where the user incrementally builds a list of selected items |
customeditabletable |
Inline-editable grids with typed cell inputs |
customdropdowndatafetchpaginated |
Single-value pick from a large paginated list when a dropdown UX is sufficient |
| Prop | Type | Required? | Description |
|---|---|---|---|
columns |
array |
required | Column definitions — each entry: { "label": "Display Label", "key": "dot.notation.path", "sortable": false, "width": "auto", "nowrap": false } |
dataType |
"STATIC" | "DYNAMIC" |
optional | How data is sourced; default "STATIC". |
rows |
array |
required (STATIC) | Row data; always set via expressions at runtime, never hardcoded. |
dataset |
object |
required (DYNAMIC) | Direct URL fetch configuration (see below). |
useBaseUrl |
boolean |
optional | Prepend API gateway base URL to dataset.url. |
tableTitle |
string |
optional | Heading rendered above the table. |
required |
boolean |
optional | Always false. The required expression controls the runtime value. |
defaultRequired |
boolean |
optional | Used with the conditional required expression pattern (see below). |
isSelectable |
boolean |
optional | If true, rows can be clicked and the selection is written to the form control; default false. |
maxSelectable |
number |
optional | Maximum rows the user can select; default Infinity. |
selectionOutputKey |
string |
optional | Model key where the selected row value is written; defaults to field.key. |
selectionOutputPath |
string |
optional | Dot-notation path within the selected row to extract before writing to the model. |
isSortVisible |
boolean |
optional | Show sort controls. |
isSearchVisible |
boolean |
optional | Show search input. |
paginationVisible |
boolean |
optional | Show pagination controls. |
paginationInsideTable |
boolean |
optional | Render pagination inside the table element. |
pageSizes |
array |
optional | Available page size choices; default [10, 50, 100]. |
showDropdown |
boolean |
optional | Show a dropdown control in the table toolbar. |
roundedTable |
boolean |
optional | Apply rounded corners styling. |
searchPlaceholder |
string |
optional | Placeholder for the search input; default "Search". |
noDataMessage |
string |
optional | Message shown when no rows exist; default "No data available". |
tableClass |
string |
optional | CSS class applied to the <table> element; default "table". |
dataset object (when dataType: "DYNAMIC")| Field | Type | Required? | Description |
|---|---|---|---|
url |
string |
required | Direct API URL; not routed through the integration gateway. |
dataField |
string |
optional | Dot-notation path to the rows array in the response. |
httpMethod |
"POST" | "GET" |
optional | HTTP method; defaults to GET. |
params |
object |
optional | Initial request params including page and size. |
headers |
object |
optional | Custom HTTP headers. |
searching |
boolean |
optional | If true, search box triggers a new API call. |
searchField |
string |
optional | Request param key for the search term. |
isSelectable: true)When the table is used as a mandatory selection input, include the same conditional required expression used by other components:
"expressions": {
"props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
}
The expression reads defaultRequired and automatically becomes false when the field is hidden.
{
"key": "PARCELS",
"type": "customdatasettable",
"props": {
"label": "Parcels",
"dataType": "STATIC",
"rows": [],
"isSelectable": false,
"isSearchVisible": false,
"isSortVisible": false,
"paginationVisible": false,
"noDataMessage": "No parcels found",
"columns": [
{ "label": "Parcel ID", "key": "parcelId" },
{ "label": "Area (m²)", "key": "area" }
]
},
"expressions": {
"props.rows": "model?.FETCHED_PARCELS || []"
}
}
The user must pick a row; the conditional required expression ensures hidden rows don't block submission.
{
"key": "COMPANY_MANAGERS_TABLE",
"type": "customdatasettable",
"props": {
"label": "Select executive management to be beneficial owner",
"dataType": "STATIC",
"rows": [],
"required": false,
"defaultRequired": true,
"isSelectable": true,
"isSearchVisible": false,
"isSortVisible": false,
"paginationVisible": false,
"noDataMessage": "No managers found",
"columns": [
{ "label": "Document No", "key": "document_number" },
{ "label": "Name", "key": "name" },
{ "label": "Position", "key": "type" }
]
},
"expressions": {
"hide": "!(model?.SHOW_MANAGER_SELECTION === 'Yes')",
"props.rows": "model?.STUB_ALL_MANAGERS || []",
"props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
},
"validation": {
"messages": {
"required": "This field is required."
}
}
}
Data is fetched directly from a backend URL with server-side pagination.
{
"key": "DISTRICT_STATS",
"type": "customdatasettable",
"props": {
"label": "District Statistics",
"dataType": "DYNAMIC",
"useBaseUrl": true,
"isSelectable": false,
"paginationVisible": true,
"noDataMessage": "No statistics available",
"dataset": {
"url": "/api/v1/districts/stats",
"dataField": "data.stats",
"httpMethod": "GET",
"params": {
"page": 0,
"size": 10
}
},
"columns": [
{ "label": "District", "key": "districtName" },
{ "label": "Total Applications", "key": "totalApplications" },
{ "label": "Approved", "key": "approved" },
{ "label": "Pending", "key": "pending" }
]
}
}
props.rows as a static array — rows must always be set at runtime via expressions (e.g. "props.rows": "model?.someKey || []").customdatasettable with dataType: "DYNAMIC" and an integration gateway endpoint — this component calls the URL directly without the gateway wrapper; use customdatatable with dataset.endpointCode instead.columns[].key (dot-notation path into the row object) with a Formly field key — key here is a path into the data row, not a form field reference.isSelectable: true without required/defaultRequired and a validation message when row selection is mandatory — the table appears interactive but the form submits with no value.isSelectable: true without selectionOutputKey when the field key is not the intended model target — the selection is written to the field key by default.paginationVisible: true when using dataType: "DYNAMIC" — pagination controls won't appear even though page/size params are sent.key is UPPER_SNAKE_CASE and unique across the entire formprops.label is present, unique, and correctly casedcolumns use the { "label": "...", "key": "..." } shape (note: opposite of customdatatable)props.rows is set via expressions, never hardcodedisSelectable: true: required: false, defaultRequired is set, and expressions["props.required"] is presentisSelectable: true and row data should be transformed: selectionOutputKey and/or selectionOutputPath are setdataType: "DYNAMIC" uses a direct URL (not the integration gateway)validation.messages.required is present whenever the table is a required inputcustomdatasettable when the data must route through the integration gateway (use customdatatable instead)