App Builder Components
Complete reference for all App Builder components
Component Structure
Section titled “Component Structure”Every component follows this structure:
{ "id": "unique-id", "type": "component-type", "visible": "{{ optional.expression }}", "width": "auto", "props": { // Component-specific properties }}Common Properties
Section titled “Common Properties”| Property | Type | Description |
|---|---|---|
id | string | Unique identifier within the page |
type | string | Component type (see below) |
visible | string | Expression that controls visibility |
width | string | auto, full, 1/2, 1/3, 1/4, 2/3, 3/4 |
loadingWorkflows | string[] | Workflow IDs - shows skeleton while any are executing |
props | object | Component-specific configuration |
Layout Containers
Section titled “Layout Containers”Horizontal flex container.
{ "type": "row", "gap": 16, "padding": 0, "align": "center", "justify": "between", "children": []}| Property | Type | Default | Description |
|---|---|---|---|
gap | number | 0 | Space between children (pixels) |
padding | number | 0 | Internal padding (pixels) |
align | string | stretch | start, center, end, stretch |
justify | string | start | start, center, end, between, around |
children | array | [] | Nested layouts or components |
Column
Section titled “Column”Vertical flex container.
{ "type": "column", "gap": 16, "padding": 0, "align": "stretch", "children": []}Same properties as Row.
CSS grid container.
{ "type": "grid", "columns": 3, "gap": 16, "padding": 0, "children": []}| Property | Type | Default | Description |
|---|---|---|---|
columns | number | 2 | Number of grid columns |
gap | number | 0 | Space between cells (pixels) |
padding | number | 0 | Internal padding (pixels) |
children | array | [] | Nested layouts or components |
Display Components
Section titled “Display Components”Heading
Section titled “Heading”{ "type": "heading", "props": { "text": "Welcome, {{ user.name }}", "level": 1, "className": "text-blue-600" }}| Property | Type | Default | Description |
|---|---|---|---|
text | string | required | Heading text (supports expressions) |
level | number | 1 | 1-6, maps to h1-h6 |
className | string | - | Additional CSS classes |
{ "type": "text", "props": { "text": "Total items: {{ data.items.length }}", "label": "Summary", "className": "text-muted-foreground" }}| Property | Type | Default | Description |
|---|---|---|---|
text | string | required | Text content (supports expressions) |
label | string | - | Optional label above text |
className | string | - | Additional CSS classes |
Renders sanitized HTML content.
{ "type": "html", "props": { "content": "<p>Custom <strong>formatted</strong> content</p>", "className": "prose" }}| Property | Type | Default | Description |
|---|---|---|---|
content | string | required | HTML content (sanitized) |
className | string | - | Additional CSS classes |
{ "type": "badge", "props": { "text": "{{ row.status }}", "variant": "default" }}| Property | Type | Default | Description |
|---|---|---|---|
text | string | required | Badge text (supports expressions) |
variant | string | default | default, secondary, destructive, outline |
className | string | - | Additional CSS classes |
Progress
Section titled “Progress”{ "type": "progress", "props": { "value": "{{ data.completion }}", "showLabel": true }}| Property | Type | Default | Description |
|---|---|---|---|
value | number/string | required | 0-100 (supports expressions) |
showLabel | boolean | false | Show percentage label |
className | string | - | Additional CSS classes |
{ "type": "image", "props": { "src": "{{ data.user.avatarUrl }}", "alt": "User avatar", "maxWidth": 200, "maxHeight": 200, "objectFit": "cover" }}| Property | Type | Default | Description |
|---|---|---|---|
src | string | required | Image URL (supports expressions) |
alt | string | - | Alt text for accessibility |
maxWidth | number/string | - | Maximum width |
maxHeight | number/string | - | Maximum height |
objectFit | string | contain | contain, cover, fill, none |
className | string | - | Additional CSS classes |
StatCard
Section titled “StatCard”Dashboard statistics card.
{ "type": "stat-card", "loadingWorkflows": ["stats-workflow-id"], "props": { "title": "Total Revenue", "value": "${{ data.stats.revenue }}", "description": "This month", "icon": "dollar-sign", "trend": { "value": "+12%", "direction": "up" }, "onClick": { "type": "navigate", "navigateTo": "/reports/revenue" } }}| Property | Type | Default | Description |
|---|---|---|---|
title | string | required | Card title |
value | string | required | Main value (supports expressions) |
description | string | - | Subtitle text |
icon | string | - | Lucide icon name |
trend.value | string | - | Trend indicator text |
trend.direction | string | - | up, down, neutral |
onClick | object | - | Click action (navigate or workflow) |
className | string | - | Additional CSS classes |
Container with optional header.
{ "type": "card", "props": { "title": "User Details", "description": "View and edit user information", "children": [] }}| Property | Type | Default | Description |
|---|---|---|---|
title | string | - | Card header title |
description | string | - | Card header description |
children | array | [] | Nested layouts/components |
className | string | - | Additional CSS classes |
Divider
Section titled “Divider”{ "type": "divider", "props": { "orientation": "horizontal" }}| Property | Type | Default | Description |
|---|---|---|---|
orientation | string | horizontal | horizontal, vertical |
className | string | - | Additional CSS classes |
Spacer
Section titled “Spacer”{ "type": "spacer", "props": { "size": 32 }}| Property | Type | Default | Description |
|---|---|---|---|
size | number/string | 16 | Space size in pixels |
className | string | - | Additional CSS classes |
Data Components
Section titled “Data Components”DataTable
Section titled “DataTable”Full-featured data table with sorting, pagination, and actions.
{ "type": "data-table", "props": { "dataSource": "customers", "cacheKey": "customers-table", "columns": [ { "key": "name", "header": "Name", "sortable": true }, { "key": "email", "header": "Email" }, { "key": "status", "header": "Status", "type": "badge", "badgeColors": { "active": "green", "inactive": "gray", "pending": "yellow" } }, { "key": "createdAt", "header": "Created", "type": "date" } ], "searchable": true, "paginated": true, "pageSize": 20, "selectable": true, "onRowClick": { "type": "navigate", "navigateTo": "/customers/{{ row.id }}" }, "rowActions": [ { "label": "", "icon": "Eye", "onClick": { "type": "navigate", "navigateTo": "/customers/{{ row.id }}" } }, { "label": "Edit", "icon": "Pencil", "onClick": { "type": "navigate", "navigateTo": "/customers/{{ row.id }}/edit" } }, { "label": "Delete", "icon": "Trash", "variant": "destructive", "disabled": "{{ row.status == 'active' }}", "onClick": { "type": "workflow", "workflowId": "delete_customer", "actionParams": { "customerId": "{{ row.id }}" } }, "confirm": { "title": "Delete Customer", "message": "Are you sure you want to delete {{ row.name }}?", "confirmLabel": "Delete", "cancelLabel": "Cancel" } } ], "headerActions": [ { "label": "Export", "icon": "Download", "onClick": { "type": "workflow", "workflowId": "export_customers" } } ], "emptyMessage": "No customers found" }}| Property | Type | Default | Description |
|---|---|---|---|
cacheKey | string | - | Persist table data across page navigations (shows refresh button) |
Column Definition
Section titled “Column Definition”| Property | Type | Description |
|---|---|---|
key | string | Data field path (dot notation: user.name) |
header | string | Column header text |
type | string | text, number, date, badge |
width | number/string | Column width |
sortable | boolean | Enable sorting |
badgeColors | object | Map values to colors (for badge type) |
Row/Header Action
Section titled “Row/Header Action”| Property | Type | Description |
|---|---|---|
label | string | Action button label (empty string + icon = icon-only button with tooltip) |
icon | string | Lucide icon name (PascalCase, e.g., Eye, Pencil, Trash) |
variant | string | default, destructive, outline, ghost |
visible | string | Visibility expression |
disabled | string | Disabled expression (e.g., {{ row.locked }}) |
onClick | object | Action configuration |
confirm | object | Confirmation dialog |
Tabbed content container.
{ "type": "tabs", "props": { "defaultTab": "overview", "orientation": "horizontal", "items": [ { "id": "overview", "label": "Overview", "icon": "home", "content": { "type": "column", "children": [] } }, { "id": "settings", "label": "Settings", "icon": "settings", "content": { "type": "column", "children": [] } } ] }}| Property | Type | Description |
|---|---|---|
defaultTab | string | ID of initially active tab |
orientation | string | horizontal, vertical |
items | array | Tab definitions |
Tab Item
Section titled “Tab Item”| Property | Type | Description |
|---|---|---|
id | string | Unique tab identifier |
label | string | Tab button label |
icon | string | Lucide icon name |
content | object | Layout container for tab content |
FileViewer
Section titled “FileViewer”Display files inline, in modal, or as download.
{ "type": "file-viewer", "props": { "src": "{{ data.document.url }}", "fileName": "{{ data.document.name }}", "mimeType": "application/pdf", "displayMode": "inline", "maxWidth": 800, "maxHeight": 600, "showDownloadButton": true }}| Property | Type | Default | Description |
|---|---|---|---|
src | string | required | File URL (supports expressions) |
fileName | string | - | Display name for file |
mimeType | string | - | MIME type (auto-detected if omitted) |
displayMode | string | inline | inline, modal, download |
maxWidth | number/string | - | Maximum display width |
maxHeight | number/string | - | Maximum display height |
showDownloadButton | boolean | true | Show download button |
downloadLabel | string | Download | Download button text |
Form Input Components
Section titled “Form Input Components”Form inputs automatically register their values in the expression context under {{ field.fieldId }}.
TextInput
Section titled “TextInput”{ "type": "text-input", "props": { "fieldId": "customerName", "label": "Customer Name", "placeholder": "Enter customer name", "defaultValue": "{{ data.customer.name }}", "required": true, "disabled": "{{ !user.canEdit }}", "inputType": "text", "minLength": 2, "maxLength": 100, "pattern": "^[A-Za-z\\s]+$" }}| Property | Type | Default | Description |
|---|---|---|---|
fieldId | string | required | Unique field identifier |
label | string | - | Field label |
placeholder | string | - | Placeholder text |
defaultValue | string | - | Initial value (supports expressions) |
required | boolean | false | Field is required |
disabled | boolean/string | false | Disable field (supports expressions) |
inputType | string | text | text, email, password, url, tel |
minLength | number | - | Minimum character length |
maxLength | number | - | Maximum character length |
pattern | string | - | Regex validation pattern |
NumberInput
Section titled “NumberInput”{ "type": "number-input", "props": { "fieldId": "quantity", "label": "Quantity", "placeholder": "0", "defaultValue": 1, "required": true, "min": 1, "max": 100, "step": 1 }}| Property | Type | Default | Description |
|---|---|---|---|
fieldId | string | required | Unique field identifier |
label | string | - | Field label |
placeholder | string | - | Placeholder text |
defaultValue | number/string | - | Initial value |
required | boolean | false | Field is required |
disabled | boolean/string | false | Disable field |
min | number | - | Minimum value |
max | number | - | Maximum value |
step | number | 1 | Increment step |
Select
Section titled “Select”{ "type": "select", "props": { "fieldId": "department", "label": "Department", "placeholder": "Select department", "required": true, "options": [ { "label": "Engineering", "value": "eng" }, { "label": "Sales", "value": "sales" }, { "label": "Support", "value": "support" } ] }}Static Options
Section titled “Static Options”| Property | Type | Description |
|---|---|---|
options | array | [{ label, value }, ...] |
Dynamic Options (from data source)
Section titled “Dynamic Options (from data source)”{ "type": "select", "props": { "fieldId": "category", "label": "Category", "optionsSource": "categories", "valueField": "id", "labelField": "name" }}| Property | Type | Default | Description |
|---|---|---|---|
optionsSource | string | - | Data source ID |
valueField | string | value | Field for option value |
labelField | string | label | Field for option label |
Checkbox
Section titled “Checkbox”{ "type": "checkbox", "props": { "fieldId": "agreeToTerms", "label": "I agree to the terms and conditions", "description": "You must agree to continue", "defaultChecked": false, "required": true }}| Property | Type | Default | Description |
|---|---|---|---|
fieldId | string | required | Unique field identifier |
label | string | required | Checkbox label |
description | string | - | Help text below label |
defaultChecked | boolean | false | Initial checked state |
required | boolean | false | Must be checked |
disabled | boolean/string | false | Disable checkbox |
Interactive Components
Section titled “Interactive Components”Button
Section titled “Button”{ "type": "button", "props": { "label": "Save Changes", "actionType": "workflow", "workflowId": "save_customer", "actionParams": { "id": "{{ variables.customerId }}", "name": "{{ field.customerName }}", "email": "{{ field.customerEmail }}" }, "onComplete": [ { "type": "navigate", "navigateTo": "/customers" } ], "variant": "default", "size": "default", "disabled": "{{ !field.customerName }}" }}| Property | Type | Default | Description |
|---|---|---|---|
label | string | required | Button text (supports expressions) |
actionType | string | required | navigate, workflow, submit, custom |
navigateTo | string | - | Target path (for navigate) |
workflowId | string | - | Workflow to execute |
actionParams | object | - | Parameters for workflow |
onComplete | array | - | Actions after workflow completes |
variant | string | default | default, destructive, outline, secondary, ghost, link |
size | string | default | default, sm, lg |
disabled | boolean/string | false | Disable button (supports expressions) |
Submit Action
Section titled “Submit Action”The submit action collects all field values and sends them to a workflow:
{ "type": "button", "props": { "label": "Submit Form", "actionType": "submit", "workflowId": "process_form", "actionParams": { "extraData": "{{ variables.context }}" } }}This sends { customerName: "...", customerEmail: "...", extraData: "..." } to the workflow.
{ "type": "modal", "props": { "title": "Create Customer", "description": "Add a new customer to the system", "triggerLabel": "New Customer", "triggerVariant": "default", "size": "lg", "content": { "type": "column", "gap": 16, "children": [ { "type": "text-input", "props": { "fieldId": "name", "label": "Name", "required": true } }, { "type": "text-input", "props": { "fieldId": "email", "label": "Email", "inputType": "email" } } ] }, "footerActions": [ { "label": "Create", "actionType": "submit", "workflowId": "create_customer", "closeOnClick": true } ], "showCloseButton": true }}| Property | Type | Default | Description |
|---|---|---|---|
title | string | required | Modal title |
description | string | - | Modal description |
triggerLabel | string | required | Button text to open modal |
triggerVariant | string | default | Trigger button variant |
triggerSize | string | default | Trigger button size |
size | string | default | sm, default, lg, xl, full |
content | object | required | Layout container for modal body |
footerActions | array | - | Action buttons in footer |
showCloseButton | boolean | true | Show X close button |
Form Integration Components
Section titled “Form Integration Components”FormEmbed
Section titled “FormEmbed”Embed an existing form from the Forms system.
{ "type": "form-embed", "props": { "formId": "contact-form-uuid", "showTitle": true, "showDescription": true, "onSubmit": [ { "type": "set-variable", "variableName": "lastSubmission", "variableValue": "{{ workflow.result }}" }, { "type": "refresh-table", "dataSourceKey": "submissions" } ] }}| Property | Type | Default | Description |
|---|---|---|---|
formId | string | required | Form UUID to embed |
showTitle | boolean | false | Show form title |
showDescription | boolean | false | Show form description |
showProgress | boolean | false | Show execution progress |
onSubmit | array | - | Actions after form submits |
FormGroup
Section titled “FormGroup”Visual grouping for form inputs.
{ "type": "form-group", "props": { "label": "Contact Information", "description": "Enter your contact details", "required": true, "direction": "column", "gap": 12, "children": [ { "type": "text-input", "props": { "fieldId": "phone", "label": "Phone" } }, { "type": "text-input", "props": { "fieldId": "address", "label": "Address" } } ] }}| Property | Type | Default | Description |
|---|---|---|---|
label | string | - | Group label |
description | string | - | Help text |
required | boolean | false | Mark group as required |
direction | string | column | row, column |
gap | number | 8 | Space between children |
children | array | [] | Nested components |
Icon Reference
Section titled “Icon Reference”Components that accept an icon property use Lucide icons. Common icons:
| Icon | Name |
|---|---|
| Home | home |
| Settings | settings |
| User | user |
| Users | users |
| Plus | plus |
| Pencil | pencil |
| Trash | trash |
| Download | download |
| Upload | upload |
| Search | search |
| Check | check |
| X | x |
| ChevronRight | chevron-right |
| ArrowRight | arrow-right |
mail | |
| Phone | phone |
| Calendar | calendar |
| Clock | clock |
| DollarSign | dollar-sign |
| BarChart | bar-chart |
| FileText | file-text |
| Folder | folder |