#Widget Catalogue

Widgets are the building blocks of an app dashboard page. Each is one entry in a page's widgets record — widgetComponent selects the widget, config is its options (config values may carry {{ … }} smart values, see Smart Values):

"widgets": {
  "tasks": { "widgetComponent": "data_grid", "config": { "header": "Open tasks", "columns": [ … ] } }
}

For the structure that holds widgets (dashboards → pages → widgets) see App spec structure.

#A real app, rendered

Everything below renders with the actual app widgets — this is a live Tasks dashboard (a heading, a task table, and a create-task form), not a screenshot:

Loading live app preview…
{
  "title": "Tasks · main dashboard",
  "widgets": [
    {
      "widgetName": "header",
      "config": {
        "text": "Tasks",
        "headerLevel": 1
      }
    },
    {
      "widgetName": "table",
      "config": {
        "header": "Open tasks",
        "columns": [
          {
            "field": "title",
            "header": "Task",
            "type": "string"
          },
          {
            "field": "state",
            "header": "State",
            "type": "string"
          },
          {
            "field": "priority",
            "header": "Priority",
            "type": "number"
          }
        ],
        "rows": [
          {
            "id": "t1",
            "title": "Draft kickoff brief",
            "state": "doing",
            "priority": 1
          },
          {
            "id": "t2",
            "title": "Set up CI",
            "state": "todo",
            "priority": 2
          },
          {
            "id": "t3",
            "title": "Write API smoke test",
            "state": "done",
            "priority": 3
          }
        ]
      }
    },
    {
      "widgetName": "form",
      "config": {
        "header": "New task",
        "fields": [
          {
            "id": "title",
            "label": "Task title",
            "type": "string",
            "required": true,
            "placeholder": "What needs doing?"
          },
          {
            "id": "state",
            "label": "State",
            "type": "string",
            "options": [
              {
                "label": "To do",
                "value": "todo"
              },
              {
                "label": "Doing",
                "value": "doing"
              },
              {
                "label": "Done",
                "value": "done"
              }
            ]
          },
          {
            "id": "priority",
            "label": "Priority",
            "type": "number",
            "min": 1,
            "max": 5
          }
        ],
        "submit": {
          "label": "Add task"
        }
      }
    }
  ]
}

This page uses the table widget (its rows are inline, so the preview is self-contained). In a production app the server-resolved data_grid does the same job at scale — fetching rows from a live dataSource, paginating, and carrying row actions. The form submits a command and buttons navigate or run actions; previews here are visual, so interactions are inert.

#The 13 widgets

A static (or smart-valued) heading.

Field Type Req Notes
text string Heading text (may be {{ }}).
headerLevel int 1–3 Visual level; defaults to 1.
Loading live widget preview…
{
  "widgetName": "header",
  "config": {
    "text": "Vessels",
    "headerLevel": 2
  }
}

#data_grid

The workhorse: a paginated, server-resolved grid with row + bulk actions and cross-widget filtering. Columns read row.attributes[field].

Field Type Req Notes
dataSource dataSource $query / $http / $rows / $typeSchema producer.
columns array { type, field, header }field reads the entity's attribute.
actions / leftActions rowAction[] Per-row buttons; each carries a command step-sequence.
selectable boolean Checkbox column; checked ids round-trip as thisWidget.selectedRows.
chips object Filter chips.
pageSize / paginate number / boolean Page size + keyset paging toggle.
header, noResultsMessage string Copy.

A data_grid resolves its rows from the live dataSource at render time, so it populates in a running app (the live preview above uses the inline-row table widget to stand in for it).

#table

A simpler, client-side table over inline rows (no server fetch / pagination). Columns read each row flat (row[field]).

Field Type Req Notes
columns array { field, header, type } — read flat from each row.
rows array Inline rows (often a {{ }}/$jsonata projection).
actions / leftActions rowAction[] Per-row buttons (command).
groupBy object Group rows under headings.
header, noResultsMessage string Copy.
Loading live widget preview…
{
  "widgetName": "table",
  "config": {
    "header": "Recent",
    "columns": [
      {
        "field": "name",
        "header": "Name",
        "type": "string"
      },
      {
        "field": "status",
        "header": "Status",
        "type": "string"
      }
    ],
    "rows": [
      {
        "id": "1",
        "name": "Aurora",
        "status": "active"
      },
      {
        "id": "2",
        "name": "Borealis",
        "status": "docked"
      }
    ]
  }
}

#form

An input form that submits a command. Fields are string / number / boolean / array; a select is a string field with static options.

Field Type Req Notes
fields array { id, label, type, required?, options?, … }.
submit object { label } — the primary submit button.
buttons array Additional buttons, each with a command.
initialValues record Seed values per field.
inline boolean Inline (vs stacked) layout.
Loading live widget preview…
{
  "widgetName": "form",
  "config": {
    "header": "New task",
    "fields": [
      {
        "id": "title",
        "label": "Title",
        "type": "string",
        "required": true
      },
      {
        "id": "priority",
        "label": "Priority",
        "type": "number"
      }
    ],
    "submit": {
      "label": "Create"
    }
  }
}

#page_tabs

A row of tab buttons that navigate between pages of the dashboard.

Field Type Req Notes
tabs array { label, page }[] — each tab navigates to a page key.
Loading live widget preview…
{
  "widgetName": "page_tabs",
  "config": {
    "tabs": [
      {
        "label": "Overview",
        "page": "root"
      },
      {
        "label": "Details",
        "page": "detail"
      },
      {
        "label": "Activity",
        "page": "activity"
      }
    ]
  }
}

#section_switcher

A button group that writes a page.data key; sections gate visibility on it via $if (no navigation).

Field Type Req Notes
stateKey string The page.data key this switcher writes.
options array { label, value }[] — the selectable sections.
Loading live widget preview…
{
  "widgetName": "section_switcher",
  "config": {
    "stateKey": "view",
    "options": [
      {
        "label": "List",
        "value": "list"
      },
      {
        "label": "Board",
        "value": "board"
      }
    ]
  }
}

A breadcrumb trail — explicit crumbs or an entity ancestry chain, with an optional refresh button.

Field Type Req Notes
crumbs array Explicit { label, page } crumbs.
ancestry object { entityType, entityId, ancestors: [{ type, labelAttr }] } — derive from parents.
refresh boolean Append a ↻ button that re-renders the page.
Loading live widget preview…
{
  "widgetName": "breadcrumbs",
  "config": {
    "crumbs": [
      {
        "label": "Vessels",
        "page": {
          "id": "vessels"
        }
      },
      {
        "label": "MV Northern Star",
        "page": {
          "id": "vessel",
          "params": {
            "id": "v-100"
          }
        }
      },
      {
        "label": "Voyage 2025-0142"
      }
    ],
    "refresh": true
  }
}

#entity_info

A labelled read-only field list for one entity (a definition-list card).

Field Type Req Notes
entityType string Entity type to resolve.
entityId string Entity id (usually {{ page.params.id }}).
fields array { label, attr }[] — label + attribute, in order.
header string Optional card heading.
Loading live widget preview…
{
  "widgetName": "entity_info",
  "config": {
    "header": "Vessel",
    "entityType": "Vessel",
    "entityId": "v1",
    "fields": [
      {
        "label": "Name",
        "attr": "name"
      },
      {
        "label": "IMO",
        "attr": "imo"
      },
      {
        "label": "Flag",
        "attr": "flag"
      }
    ]
  },
  "build": {
    "instance": {
      "id": "v1",
      "attributes": {
        "name": "Aurora",
        "imo": "9876543",
        "flag": "Panama"
      }
    }
  }
}

Lists an entity's related collections as grouped sections — config-driven, so adding a collection is a config-only change.

Field Type Req Notes
entityId string The detail entity id.
collections array { type, via }[] — related type + relationship rule.
collapsible boolean Render each section collapsible.
header string Optional heading.

The preview supplies sample rows that the engine would normally resolve from each collection's relationship rule:

Loading live widget preview…
{
  "widgetName": "related_collections",
  "config": {
    "entityId": "voyage-1",
    "header": "Related",
    "collections": [
      {
        "label": "Tasks",
        "type": "Task",
        "via": "Voyage",
        "columns": [
          {
            "field": "title",
            "header": "Task"
          },
          {
            "field": "status",
            "header": "Status",
            "type": "tag"
          },
          {
            "field": "due",
            "header": "Due",
            "type": "date"
          }
        ]
      },
      {
        "label": "Alerts",
        "type": "Alert",
        "via": "Voyage",
        "columns": [
          {
            "field": "summary",
            "header": "Alert"
          },
          {
            "field": "severity",
            "header": "Severity",
            "type": "tag"
          }
        ],
        "noResultsMessage": "No alerts"
      }
    ]
  },
  "build": {
    "relatedCollections": [
      {
        "rows": [
          {
            "title": "Submit port docs",
            "status": "open",
            "due": "2025-09-10"
          },
          {
            "title": "Confirm berth",
            "status": "done",
            "due": "2025-09-08"
          }
        ]
      },
      {
        "rows": [
          {
            "summary": "Late ETA",
            "severity": "high"
          }
        ]
      }
    ]
  }
}

#actions

A free-standing button group (not bound to a row), e.g. a page footer bar.

Field Type Req Notes
actions array { label, command, icon?, variant? }[] — each runs a step-sequence.
asFooter boolean Pin to a footer bar.
Loading live widget preview…
{
  "widgetName": "actions",
  "config": {
    "actions": [
      {
        "label": "Refresh",
        "command": []
      },
      {
        "label": "Export CSV",
        "command": []
      }
    ]
  }
}

#action_bar

A status-catalog action bar for one entity (drives a command per catalog item).

Field Type Req Notes
entityType, entityId string The bound entity.
catalog catalogSource Status/item catalog source.
instances instanceSource Per-item instance source.
invoke object { command, label? } — the step-sequence a bar action runs.
Loading live widget preview…
{
  "widgetName": "action_bar",
  "config": {
    "entityType": "Voyage",
    "entityId": "voyage-1",
    "catalog": {
      "bindingType": "VoyageStepBinding",
      "boundTypeAttr": "bound_type",
      "definitionType": "VoyageStepDefinition",
      "definitionRefAttr": "definition_key",
      "keyAttr": "key",
      "labelAttr": "label"
    },
    "instances": {
      "type": "VoyageStepInstance",
      "parentKeyAttr": "voyage_key",
      "keyAttr": "step_key",
      "stateAttr": "state"
    },
    "invoke": {
      "label": "Initiate {label}",
      "command": [
        {
          "kind": "refresh"
        }
      ]
    }
  },
  "build": {
    "process": {
      "boundType": "Voyage",
      "catalog": [
        {
          "key": "departure_clearance",
          "label": "Departure clearance",
          "sortOrder": 0,
          "secondary": false,
          "hideInStatusTable": false,
          "dependsOn": [],
          "condition": null,
          "enabled": true,
          "attrs": {
            "key": "departure_clearance"
          }
        },
        {
          "key": "pilot_booking",
          "label": "Pilot booking",
          "sortOrder": 1,
          "secondary": true,
          "hideInStatusTable": false,
          "dependsOn": [],
          "condition": null,
          "enabled": true,
          "attrs": {
            "key": "pilot_booking"
          }
        }
      ],
      "states": {},
      "context": {
        "entity": {
          "metadata": {}
        },
        "parent": null,
        "completed_job_ids": [],
        "permissions": [],
        "user": {}
      },
      "parent": {
        "id": "voyage-1",
        "type": "Voyage",
        "key": "2025-0142"
      }
    }
  }
}

#status_checklist

A checklist of catalog items with per-item status + row actions.

Field Type Req Notes
entityType, entityId string The bound entity.
catalog catalogSource Item catalog.
instances instanceSource Per-item instances.
statusMap object Status → display mapping.
actions array Per-row actions (command).
Loading live widget preview…
{
  "widgetName": "status_checklist",
  "config": {
    "entityType": "Voyage",
    "entityId": "voyage-1",
    "header": "Voyage checklist",
    "catalog": {
      "bindingType": "VoyageStepBinding",
      "boundTypeAttr": "bound_type",
      "definitionType": "VoyageStepDefinition",
      "definitionRefAttr": "definition_key",
      "keyAttr": "key",
      "labelAttr": "label"
    },
    "instances": {
      "type": "VoyageStepInstance",
      "parentKeyAttr": "voyage_key",
      "keyAttr": "step_key",
      "stateAttr": "state"
    },
    "statusMap": {
      "DONE": {
        "emoji": "🟢",
        "label": "Done"
      },
      "READY": {
        "emoji": "🔴",
        "label": "To do"
      }
    },
    "actions": [
      {
        "id": "start",
        "label": "Start",
        "enabledWhen": [
          {
            "property": "state",
            "operator": "equals",
            "value": "READY"
          }
        ],
        "command": [
          {
            "kind": "refresh"
          }
        ]
      }
    ]
  },
  "build": {
    "process": {
      "boundType": "Voyage",
      "catalog": [
        {
          "key": "departure_clearance",
          "label": "Departure clearance",
          "sortOrder": 0,
          "secondary": false,
          "hideInStatusTable": false,
          "dependsOn": [],
          "condition": null,
          "enabled": true,
          "attrs": {
            "key": "departure_clearance"
          }
        },
        {
          "key": "cargo_manifest",
          "label": "Cargo manifest",
          "sortOrder": 1,
          "secondary": false,
          "hideInStatusTable": false,
          "dependsOn": [],
          "condition": null,
          "enabled": true,
          "attrs": {
            "key": "cargo_manifest"
          }
        }
      ],
      "states": {
        "cargo_manifest": {
          "state": "DONE",
          "stateAt": "2025-09-05T00:00:00Z",
          "attrs": {}
        }
      },
      "context": {
        "entity": {
          "metadata": {}
        },
        "parent": null,
        "completed_job_ids": [
          "cargo_manifest"
        ],
        "permissions": [],
        "user": {}
      },
      "parent": {
        "id": "voyage-1",
        "type": "Voyage",
        "key": "2025-0142"
      }
    }
  }
}

#custom_markup

An escape hatch: an authored markup tree with named action handlers.

Field Type Req Notes
markup blockElement The markup tree to render.
actionHandlers record Named handlers → step-sequences invoked from the markup.
Loading live widget preview…
{
  "widgetName": "custom_markup",
  "config": {
    "markup": {
      "type": "dataList",
      "items": [
        {
          "label": "Vessel",
          "content": "MV Northern Star"
        },
        {
          "label": "Voyage",
          "content": "2025-0142"
        },
        {
          "label": "Status",
          "content": "In transit"
        },
        {
          "label": "ETA",
          "content": "2025-09-14"
        }
      ]
    }
  }
}

Every widget above renders live on this page. The entity-bound widgets (entity_info, related_collections, status_checklist, action_bar) are shown with sample data the engine resolves at render time in a real app. The data_grid is the one widget that needs a live data source ($query/$http) — it renders its columns + actions but populates its rows only in a running app; see Apps (Bridge) for an end-to-end app.