Layouts
Layouts define the UI structure of a class — which fields, relations, actions, and navigations are shown, and in what order. Each layout has a type that determines where it is used.
Definition
{
"class": "my-project.employmentAgreement",
"type": "OBJECT_DASHBOARD",
"labelKey": "LABEL:contractDetails",
"tabPage": false,
"items": [...]
}
| Property | Type | Description |
|---|---|---|
class | TypeFQN | The class this layout applies to. |
name | string | Identifier for named layout variants (selected via ?name=xxx). |
labelKey | string | Translation key for the layout tab title. See Label keys. |
type | LayoutType | Determines where this layout is rendered. |
items | LayoutItem[] | Ordered list of items to display. |
tabPage | boolean | When true, this layout is rendered as a tab; when false (default), as the main section. |
order | integer | Controls the display sequence of panels and tabs. On OBJECT_FORM_DASHBOARD, layouts with the same order are presented as alternatives to choose from. Omit to preserve declaration order. |
condition | string | Formula expression evaluated against the current form state. The layout is hidden when the expression evaluates to false. Only meaningful on OBJECT_FORM_DASHBOARD. Omit to always show. |
create | boolean | Whether this layout is shown when creating a new object. Default: true. Only meaningful on OBJECT_FORM_DASHBOARD. |
modify | boolean | Whether this layout is shown when editing an existing object. Default: true. Only meaningful on OBJECT_FORM_DASHBOARD. |
Layout types
| Type | Description |
|---|---|
OBJECT_DASHBOARD | Main detail view for a single object. Usually has a main section and optional tab layouts for related objects. |
RELATED_OBJECT | Compact inline detail panel when an object appears as a related item. |
OBJECT_FORM_DASHBOARD | Inline creation form for a new object. |
GENERAL_DASHBOARD | Dashboard not tied to a specific object (e.g. a home or search screen). Supports named variants via name. |
CLASS_DASHBOARD | List/table overview for all objects of a class. |
NAVIGATION_PANE | Items shown in the sidebar navigation. Usually contains NAVIGATE items. |
Label keys
Labels used in layout items (headers, tabs, button captions, static text) are resolved via LabelKey strings. The format is TYPE:name, for example LABEL:contractDetails or DATA_CLASS_PLURAL:commons.document.
| Type prefix | Resolves to |
|---|---|
LABEL:key | A general translation key from generalLabels in the class translation. |
DATA_CLASS_SINGULAR:fqn | Singular name of the named class. |
DATA_CLASS_PLURAL:fqn | Plural name of the named class. |
VALUE_TYPE_LABEL:field | Label for the named value type field. |
LIST_VALUE:list:key | Label for a standard list item. |
PLAIN_TEXT:text | Literal text, no lookup performed. |
BLANK | Empty string. |
Strings without a recognized prefix are treated as PLAIN_TEXT. Inline HTML is also supported.
Layout items
Each item in items has a type field that determines its structure. When type is omitted, FIELD is assumed.
FIELD
Displays a value type field.
{ "name": "jobTitle" }
{ "type": "FIELD", "name": "salary", "header": true }
| Property | Description |
|---|---|
name | The value type name to display. |
header | When true, renders this field as the main title of the panel. |
defaultValue | Pre-filled value when creating a new object. |
HEADER
A section heading.
{ "type": "HEADER", "label": "Employment details" }
| Property | Description |
|---|---|
label | The heading text, a LabelKey string, or inline HTML. |
ACTION
A button that triggers a script, opens a report, or deletes the current object.
{ "type": "ACTION", "name": "sendInvitation", "label": "Send invitation", "actionType": "SCRIPT" }
{ "type": "ACTION", "name": "invoicePDF", "label": "Print invoice", "actionType": "REPORT" }
{ "type": "ACTION", "label": "Delete", "actionType": "REMOVE" }
| Property | Description |
|---|---|
name | The script or report name to invoke. Not required for REMOVE. |
label | Button caption or LabelKey string. |
actionType | What happens when the button is clicked. Defaults to SCRIPT when omitted. |
actionType values:
| Value | Description |
|---|---|
SCRIPT | Invokes the named script on the current object. Default when actionType is omitted. |
REPORT | Opens the named report for the current object in a new browser tab. See Reports. |
REMOVE | Deletes the current object. name is ignored. |
NAVIGATE
A navigation link to another class or screen.
{
"type": "NAVIGATE",
"class": "my-project.invoice",
"navigationType": "CLASS_DASHBOARD",
"icon": "receipt"
}
| Property | Description |
|---|---|
class | The class to navigate to. |
navigationType | Which page to open. See NavigationType below. |
icon | Optional icon identifier. |
name | Selects a named general dashboard when navigationType is DASHBOARD. |
NavigationType values:
| Value | Description |
|---|---|
CLASS_DASHBOARD | Opens the list/table page for the target class. |
OBJECT_FORM_DASHBOARD | Opens an inline creation form for the target class. |
DASHBOARD | Opens a general dashboard, optionally named via name. |
RELATION
An editable relation field.
{ "type": "RELATION", "relatedClass": "commons.company", "editBehavior": "SEARCH" }
| Property | Description |
|---|---|
relatedClass | The class of the related object. |
editBehavior | UI widget for selecting objects: SEARCH (free-text), DROPDOWN, or CHECKBOX (for multiple with few options). |
RELATED_OBJECT
Displays a related object as an inline sub-panel.
{ "type": "RELATED_OBJECT", "relatedClass": "commons.person", "name": "compact" }
| Property | Description |
|---|---|
relatedClass | The class of the related object. |
name | Selects a named layout variant on the related class (omit for default). |
RELATED_VIEW
Displays a filtered list of related objects, typically as a tab.
{
"type": "RELATED_VIEW",
"fromClass": "my-project.project",
"relatedClass": "my-project.task",
"showTitle": true
}
| Property | Description |
|---|---|
fromClass | The class the relation originates from (the current object's class). |
relatedClass | The class of the related objects to list. |
filterClass | When set, restricts the list to this subtype of relatedClass. |
showTitle | Whether to show a section heading. |
name | Named view on relatedClass to use (omit for default). |
actions | Toolbar actions available on the list. Supported values: "NEW" (add button) and "EXPORT" (export button). Defaults to ["NEW", "EXPORT"] when omitted. |
alternativeViews | Optional list of additional named views the user can switch to. Same structure as for VIEW. class defaults to relatedClass when omitted. |
SEARCH
An embedded search widget for a class.
{ "type": "SEARCH", "class": "commons.person", "showTitle": true }
| Property | Description |
|---|---|
class | The class to search within. |
showTitle | Whether to show a section heading. |
TEXT
A static text block.
{ "type": "TEXT", "label": "This section shows employment history." }
| Property | Description |
|---|---|
label | Text content, a LabelKey string, or inline HTML. |
VIEW
Embeds a named or default View for a class.
{ "type": "VIEW", "class": "my-project.task", "name": "openTasks", "showTitle": true }
| Property | Description |
|---|---|
class | The class whose view is rendered. |
name | The named view to embed (omit for the default view). |
showTitle | Whether to show a section heading. |
actions | Toolbar actions available on the view. Supported values: "NEW" (add button) and "EXPORT" (export button). Defaults to ["NEW", "EXPORT"] when omitted. |
alternativeViews | Optional list of additional named views the user can switch to. When present, a dropdown is rendered next to the filter button. |
Each entry in alternativeViews:
| Property | Description |
|---|---|
name | The named view to load when selected. |
label | Optional display text (LabelKey string or literal). Falls back to name when omitted. |
class | Optional class override. Defaults to the item's class when omitted. |
{
"type": "VIEW",
"class": "legalmanager.clientAgreement",
"alternativeViews": [
{ "name": "inactiveAgreements", "label": "Inactive" },
{ "name": "archivedAgreements", "label": "Archived" }
]
}
SOURCE
A search widget that calls a producer script and lets the user pick a result. On selection, either an actor script is invoked or the selected fields are used to prefill the form.
{
"type": "SOURCE",
"sourceName": "CompanySearch",
"parameters": [
{ "name": "countryCode", "field": "country.countryCode" }
],
"script": "importCompany"
}
| Property | Description |
|---|---|
sourceName | Name of the producer script to call — matches {sourceName} in GET /sources/{tenantId}/{sourceName}. |
parameters | List of { name, field } entries. field is a dot-notation path into the current form state (e.g. "country.countryCode"). |
script | GENERAL-scope actor script to invoke when the user selects a result. The selected result's fields are passed as script parameters. Mutually exclusive with fieldMapping. |
fieldMapping | Maps result fields to form fields for client-side prefill on selection (e.g. { "registrationNumber": "kvkNumber" }). Mutually exclusive with script. |
A SOURCE item is only useful on an OBJECT_FORM_DASHBOARD. Use script when the selection should trigger server-side logic (create/update, full data enrichment). Use fieldMapping when you just want to prefill a few fields and let the user review before submitting.
Multi-step forms
The order and condition properties turn an OBJECT_FORM_DASHBOARD into a guided multi-step flow. Each layout in the form is a step; steps are shown in order sequence as the user fills in the form.
Rules:
- Layouts without
orderare shown in declaration order after any ordered layouts. - When a step has only one layout and its condition is met, it is shown directly.
- When a step has multiple layouts and all their conditions are met, they are shown as alternatives (the user picks one).
- A layout is hidden when its
conditionevaluates tofalse.
Example: add a company via register or manually
"layouts": [
{
"type": "OBJECT_FORM_DASHBOARD",
"order": 0,
"labelKey": "LABEL:chooseCountry",
"items": [
{ "type": "RELATION", "relatedClass": "commons.country", "editBehavior": "DROPDOWN" }
]
},
{
"type": "OBJECT_FORM_DASHBOARD",
"order": 1,
"condition": "country.countryCode == 'nl' || country.countryCode == 'gb'",
"labelKey": "LABEL:searchInRegister",
"items": [
{
"type": "SOURCE",
"sourceName": "CompanySearch",
"parameters": [
{ "name": "countryCode", "field": "country.countryCode" }
],
"script": "importCompany"
}
]
},
{
"type": "OBJECT_FORM_DASHBOARD",
"order": 1,
"condition": "country != null",
"labelKey": "LABEL:companyDetails",
"items": [
{ "name": "name", "header": true },
{ "name": "kvkNumber" },
{ "name": "city" },
{ "name": "postalCode" }
]
}
]
| Step | Situation | Shown |
|---|---|---|
| 0 | Always | Country picker |
| 1 | Unsupported country selected | Manual entry form only |
| 1 | Supported country (nl/gb) | Both alternatives: "Search in register" and "Manual entry" |
When the user searches in the register and selects a result, the importCompany script runs and handles the create-or-update logic server-side. The form does not need a separate review step.
Create vs. modify forms
By default an OBJECT_FORM_DASHBOARD layout is shown for both creating and editing an object. Use the create and modify flags to restrict a layout to one operation.
| Flag | Default | Effect when false |
|---|---|---|
create | true | Layout is hidden when creating a new object |
modify | true | Layout is hidden when editing an existing object |
Example: a field only settable on create
An invitation token should only appear on the create form — once the object exists it cannot be changed.
"layouts": [
{
"class": "my-project.invitation",
"type": "OBJECT_FORM_DASHBOARD",
"modify": false,
"items": [
{ "type": "FIELD", "name": "token" },
{ "type": "FIELD", "name": "email" }
]
},
{
"class": "my-project.invitation",
"type": "OBJECT_FORM_DASHBOARD",
"create": false,
"items": [
{ "type": "FIELD", "name": "status" },
{ "type": "FIELD", "name": "email" }
]
}
]
The first layout (with "modify": false) is shown when creating a new invitation and includes the token field. The second layout (with "create": false) is shown when editing an existing invitation and shows the status field instead.
Example: a form shown for both operations
Omitting both flags (or setting both to true) shows the same layout for create and modify — the default behaviour.
{
"class": "my-project.contract",
"type": "OBJECT_FORM_DASHBOARD",
"items": [
{ "type": "FIELD", "name": "contractType" },
{ "type": "FIELD", "name": "startDate" }
]
}
Example: OBJECT_DASHBOARD layout
{
"class": "my-project.employmentAgreement",
"type": "OBJECT_DASHBOARD",
"items": [
{ "type": "HEADER", "label": "Contract details" },
{ "type": "FIELD", "name": "contractType" },
{ "type": "FIELD", "name": "salary" },
{ "type": "FIELD", "name": "hoursPerWeek" },
{ "type": "HEADER", "label": "Parties" },
{ "type": "RELATION", "relatedClass": "commons.company", "editBehavior": "SEARCH" },
{ "type": "RELATION", "relatedClass": "commons.employee", "editBehavior": "SEARCH" },
{ "type": "HEADER", "label": "Actions" },
{ "type": "ACTION", "name": "extractFromDocument", "label": "Extract from document" }
]
}
Example: OBJECT_DASHBOARD with a tab
A main section layout and a separate tab for related tasks on the same class:
[
{
"class": "my-project.project",
"type": "OBJECT_DASHBOARD",
"tabPage": false,
"items": [
{ "type": "FIELD", "name": "projectName", "header": true },
{ "type": "FIELD", "name": "startDate" },
{ "type": "FIELD", "name": "status" }
]
},
{
"class": "my-project.project",
"type": "OBJECT_DASHBOARD",
"tabPage": true,
"labelKey": "DATA_CLASS_PLURAL:my-project.task",
"items": [
{
"type": "RELATED_VIEW",
"fromClass": "my-project.project",
"relatedClass": "my-project.task",
"showTitle": false
}
]
}
]