This article describes the rules and best practices for developing libraries with custom components for App Builder.
Once you have built a zip file with custom components, add it to App Builder.
Library Structure
Each library must have the following structure:
your-library.zip
└── components/
└── component-name/
├── form.json
└── metadata.json
components:
- Root directory for all custom components in the library.
- Each subdirectory represents a single component.
component-name:
- Directory name must match the components internal name.
- Used to associate configuration files with the components runtime implementation.
form.json:
- Defines the components configuration UI in the App Builder.
- Specifies:
- Field definitions and default values.
- Tabs and form layout.
- Conditional logic using
deps. - Async selectors and data sources.
- Does not define rendering or runtime behavior.
metadata.json
- Defines display metadata for the component picker.
- Has no impact on runtime logic or render behavior.
- Has the following structure:
{
"name": "Component Name",
"icon": "mi-element"
}
name: Human-readable label shown in the App Builder.icon: Icon displayed next to the component.
1. Configure Component Properties in form.json
The form.json file defines the settings panel displayed in the App Builder.
File Structure:
{
"fields": {...}
},
"settings": {
"tabs": [
{
"name": "Tab Name",
"components": [...]
}
]
}
}
The fields section defines field defaults and special field behavior:
{
"fields": {
"simple_field": {
"default": "default_value"
},
"asset_field": {
"variable": "image",
"item_type": "asset"
},
"dataset_field": {
"variable": "dataset_id",
"item_type": "dataset",
"default": ""
}
}
}
default: Default field value.variable: Variable name for special fields.item_type:assetordataset.
Supported Form Components
FormText
Single-line text input.
{
"name": "title",
"label": "Title",
"component": "FormText",
"props": {
"placeholder": "Enter title..."
}
}
FormTextarea
Multi-line text input.
{
"name": "description",
"label": "Description",
"component": "FormTextarea",
"props": {
"rows": 3
}
}
FormRichText
Rich text editor.
{
"name": "content",
"label": "Content",
"component": "FormRichText"
}
FormSwitch
Toggle switch (Yes/No).
{
"name": "show_icon",
"label": "Show Icon",
"component": "FormSwitch",
"data": [
{ "value": "Y", "label": "Yes" },
{ "value": "N", "label": "No" }
]
}
FormToggleButtonGroup
Grouped button selector.
{
"name": "direction",
"label": "Direction",
"component": "FormToggleButtonGroup",
"props": {
"fullWidth": true,
"xs": "6"
},
"data": [
{ "value": "horizontal", "label": "Horizontal" },
{ "value": "vertical", "label": "Vertical" }
]
}
Example with icons instead of labels:
{
"name": "align",
"label": "Align",
"component": "FormToggleButtonGroup",
"props": {
"fullWidth": true,
"icons": {
"left": "builder-alignment-left",
"center": "builder-alignment-center",
"right": "builder-alignment-right"
}
},
"data": [
{ "value": "left", "label": "" },
{ "value": "center", "label": "" },
{ "value": "right", "label": "" }
]
}
FormSelect
Async dropdown backed by system data sources.
{
"name": "folder_id",
"label": "Folder",
"component": "FormSelect",
"asyncDataUrl": "/data/app/select-data?source=folder",
"props": {
"applyVirtualList": true
}
}
See the list of supported data sources in the table below.
NOTE: props.settings contains metadata about the selection, not the actual data. To retrieve the actual data (dataset rows, folders, metrics, etc.), use the corresponding API endpoints linked to the Description column.
| Source Parameter | Description |
|---|---|
?source=folder | Folders |
?source=category | Categories |
?source=favorite | Favorites |
?source=element | Elements (metrics, reports) |
?source=dataset | Datasets |
?source=dataset_column | Dataset columns (requires datasetId) |
ChooseIcon
Icon picker.
{
"name": "icon",
"label": "Icon",
"component": "ChooseIcon",
"props": {
"iconSet": ["mi"]
}
}
UploadImage
Image upload component.
{
"name": "image",
"label": "Image",
"component": "UploadImage"
}
Field definition for asset:
{
"fields": {
"image": {
"variable": "image",
"item_type": "asset"
}
}
}
Conditional Fields
Use deps to dynamically show, hide, or modify fields.
Basic Structure
{
"deps": [
{
"scope": "control",
"rules": [
{ "field": "field_name", "cond": "=", "data": "value" }
],
"effect": {
"_r_class_d-none": true
}
}
]
}
Supported Conditions
| Operator | Description |
|---|---|
= | Equals |
"" | Has any value |
Supported Effects
| Effect | Description |
|---|---|
_class_d-none | Hide field |
_r_class_d-none | Show field |
urlParams.field | Set dynamic URL parameters |
Example: Show/Hide on Toggle
{
"name": "link",
"label": "External Link",
"component": "FormText",
"props": {
"_class_d-none": true
},
"deps": [
{
"scope": "control",
"rules": [
{ "field": "navigate_to", "cond": "=", "data": "external" }
],
"effect": {
"_r_class_d-none": true
}
}
]
}
Cascading Selects
Use dependent selects to filter options based on another field’s value; e.g., Dataset → Column.
Field definitions:
{
"fields": {
"dataset_id": {
"variable": "dataset_id",
"item_type": "dataset",
"default": ""
},
"dataset_column": {
"default": ""
}
}
}
Dataset selector:
{
"name": "dataset_id",
"label": "Dataset",
"component": "FormSelect",
"asyncDataUrl": "/data/app/select-data?source=dataset",
"props": {
"applyVirtualList": true
}
}
Column selector:
{
"name": "dataset_column",
"label": "Column",
"component": "FormSelect",
"asyncDataUrl": "/data/app/select-data",
"props": {
"urlParams": {
"datasetId": "",
"source": "dataset_column"
}
},
"deps": [
{
"scope": "control",
"rules": [
{ "field": "dataset_id", "cond": "", "data": "" }
],
"effect": {
"urlParams.datasetId": "$dataset_id",
"_r_class_d-none": true
}
}
]
}
- Use
urlParamsfor dynamic API parameters. - Reference other fields using
$field_name. - Use
depsto control visibility and parameter updates.
Common Properties Reference
| Prop | Type | Description |
|---|---|---|
_class_d-none |
boolean | Hide field by default |
fullWidth |
boolean | Render field using full container width |
xs |
string | Grid column size (e.g. "6" = half width) |
placeholder |
string | Input placeholder text |
rows |
number | Number of visible rows (textarea only) |
applyVirtualList |
boolean | Enable virtual scrolling for large lists |
urlParams |
object | Dynamic URL parameters for async data requests |
iconSet |
array | Icon sets to display (e.g. ["mi"]) |
icons |
object | Map of values to icon names |
2. Upload Library to Metric Insights
See Add Library with Custom Components to App Builder for details.
NOTE: You will have to Write Code for React Custom Components.