An inline-editable tabular grid where each cell is a typed input (text, number, email, date, or select). Use when structured data has a fixed or user-managed list of rows and a known set of typed columns — such as product inventories, fee schedules, or employee contact tables.
Read Form Rules before using this component — keys, labels, required fields, expressions, visibility, and validation all follow shared conventions.
required, min/max, pattern) without rendering full Formly fields per cellInstead of customeditabletable, use… |
For… |
|---|---|
customdatatable |
Read-only display of integration-gateway data |
customdatasettable |
Read-only display of model data or direct URL fetches; row click selection |
customitemselectiontable |
Per-row Add/Remove selection workflows |
customeditableinput |
A single inline-editable cell input used as a column primitive (not a full table) |
customcascadingeditableinput |
A cascading cell input where one column's options depend on another column's value within a row |
| A regular Formly repeater | Rows with deeply nested or heterogeneous fields that don't fit a uniform cell grid |
| Prop | Type | Required? | Description |
|---|---|---|---|
label |
string |
optional | Label displayed above the table. |
rows |
array |
required | Array of row configurations — see row shape below; omit content when allowRowAddition: true (user creates rows). |
columns |
array |
required | Array of column configurations — see column shape below. |
rowColumnTitle |
string |
optional | Header text for the row-label column; only shown when showRowLabels: true. |
showRowLabels |
boolean |
optional | When true, displays a leading column with each row's label. |
allowRowAddition |
boolean |
optional | When true, shows an "Add Row" button so the user can append rows at runtime; default false. |
allowRowDeletion |
boolean |
optional | When true, shows a delete button on each row; default false. |
disabled |
boolean |
optional | When true, all cell inputs are read-only. |
customTableClass |
string |
optional | CSS class applied to the table element for custom styling. |
rows)| Key | Type | Required? | Description |
|---|---|---|---|
key |
string |
required | Unique identifier for the row — used as the key in the returned data object. |
label |
string |
required | Display label shown in the row-label column. |
disabled |
boolean |
optional | When true, all inputs in this row are disabled. |
columns)| Key | Type | Required? | Description |
|---|---|---|---|
key |
string |
required | Unique identifier for the column — used as the field name in each row's data. |
label |
string |
required | Column header text. |
type |
string |
optional | Cell input type: "text" (default), "number", "email", "date", "select". |
required |
boolean |
optional | When true, the cell must not be empty. |
disabled |
boolean |
optional | When true, all cells in this column are read-only. |
placeholder |
string |
optional | Placeholder text shown inside the cell input. |
width |
string |
optional | CSS width for the column — e.g. "150px" or "20%". |
min |
number |
optional | Minimum value — number type only. |
max |
number |
optional | Maximum value — number type only. |
pattern |
string |
optional | Regex validation pattern — text type only. |
options |
array |
required (select) | For select type — array of { "label": string, "value": any }. |
| Type | Input widget | Notes |
|---|---|---|
"text" |
Text input | Supports pattern validation |
"number" |
Numeric input | Supports min / max; value stored as number |
"email" |
Email input | Built-in email format validation |
"date" |
Date picker | Returns ISO date string (YYYY-MM-DD) |
"select" |
Searchable dropdown | Requires options array |
The component returns an object keyed by row.key, each holding an object keyed by column.key:
{
"row1": { "quantity": 100, "price": 5000, "status": "available" },
"row2": { "quantity": 50, "price": 7500, "status": "out_of_stock" }
}
A simple inventory table with fixed rows and no add/delete.
{
"key": "INVENTORY",
"type": "customeditabletable",
"props": {
"label": "Product Inventory",
"rowColumnTitle": "Product",
"showRowLabels": true,
"rows": [
{ "key": "PRODUCT_1", "label": "Laptop" },
{ "key": "PRODUCT_2", "label": "Mouse" }
],
"columns": [
{
"key": "QUANTITY",
"label": "Quantity",
"type": "number",
"required": true,
"min": 0
},
{
"key": "PRICE",
"label": "Price (RWF)",
"type": "number",
"required": true,
"min": 0
}
]
},
"validation": {
"messages": {
"required": "This field is required."
}
}
}
A fee schedule where officers add and delete rows; includes a text column with regex, a number column, and a status select.
{
"key": "FEE_SCHEDULE",
"type": "customeditabletable",
"props": {
"label": "Fee Schedule",
"allowRowAddition": true,
"allowRowDeletion": true,
"rows": [],
"columns": [
{
"key": "SERVICE_NAME",
"label": "Service Name",
"type": "text",
"required": true,
"placeholder": "Enter service name",
"width": "40%",
"pattern": "^[a-zA-Z0-9\\s\\-]+$"
},
{
"key": "FEE",
"label": "Fee (RWF)",
"type": "number",
"required": true,
"min": 0,
"placeholder": "Enter fee",
"width": "25%"
},
{
"key": "STATUS",
"label": "Status",
"type": "select",
"required": true,
"width": "25%",
"options": [
{ "label": "Active", "value": "ACTIVE" },
{ "label": "Inactive", "value": "INACTIVE" }
],
"placeholder": "Select status"
}
]
},
"validation": {
"messages": {
"required": "This field is required.",
"min": "Value must be 0 or greater.",
"pattern": "Service name contains invalid characters."
}
}
}
rows: [] when allowRowAddition: false — the table renders with no rows and the user has no way to add any; either provide a rows array with at least one item or set allowRowAddition: true.options on a select-type column — the dropdown renders empty.min / max on a text-type column — these constraints only apply to number type; they are silently ignored.pattern on a number-type column — pattern only applies to text; use min and max for numeric constraints.required: true at the component level — required on the table itself is not supported; mark individual columns as required: true.rowColumnTitle when showRowLabels: true — the row-label column header is blank.key across two columns — the returned data object overwrites one column's value; every column key must be unique within the table.key is UPPER_SNAKE_CASE and unique across the entire formprops.label is present, unique, and correctly casedcolumns[].key and rows[].key is unique within the tableselect-type columns include an options arraymin/max are only used on number columnspattern is only used on text columnsrequired: true has a matching validation.messages.requiredmin/max/pattern constraints each have matching validation messagesallowRowAddition: false and a non-empty rows array, or allowRowAddition: true (never empty rows with no add button)showRowLabels: true is paired with a rowColumnTitlecustomeditabletable when the data is read-only (use customdatatable or customdatasettable)