<a id="reference"></a>

# Reference and compatibility

The component catalog below comes directly from the Workspace compiler, so its
attributes, child rules, enumerations and defaults always match what the editor
accepts.

Conditional forms use the curated `form-predicate/1` profile. Its expressions
behave identically on the server and in the CoCoCo app, including
boolean results, dependency rules and resource limits. The server compiles XML;
the app displays the compiled result.

Use the catalog for exact syntax. No undocumented element, attribute, custom filter
or arbitrary JavaScript execution is implied by the examples.

# Workspace XML component reference

Each entry says what a component is for, where it can be used and what it may contain, then lists its attributes. The editor checks every rule shown here as you save. Some tags, such as `<field>`, mean different things in different places; those entries name their context.

## Components

### `<workspace>`

The root element of a Workspace: a screen of panels that read and edit business data. It declares shared state, server Lua handlers, data sources and the layout.

Used at the top level of a Workspace source.

Can contain: `<state>` (any number); `<handler>` (any number); `<data-source>` (any number); `<row>` or `<column>` or `<master-detail>` or `<panel>` or `<metric-panel>` or `<record-browser>` or `<record-editor>` or `<related-records>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | yes | string | — | Heading shown to users. |
| `role` | yes | string | — | The audience the workspace is for, such as Sales or Operations. |
| `xmlns:t` | no | `urn:cococo:dataxml` | — | Binds the `t:` prefix used for data bindings. Any prefix bound to `urn:cococo:dataxml` works. |
| `domains` | no | string | — | Space-separated business domains the workspace relates to. They are hints and grant no permissions. |

### `<data-source>`

Loads data for lookups without showing a panel, for example the options of a relationship picker. It loads and refreshes like a panel. It does not hide the data from anyone allowed to open the workspace.

Used inside: `<workspace>`.

Can contain: `<query>` (exactly one).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | no | string | — | Heading shown to users. |
| `wait-for` | no | string | — | Space-separated query variable names that must have a value before the panel loads. An empty value loads immediately; leaving it out waits until every top-level variable has a value. |

### `<state>`

Declares a piece of shared state, such as the selected record or a filter value, with its initial JSON value. Queries, lists, filters and forms read and write it by name.

Used inside: `<workspace>`.

Accepts text content.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `name` | yes | string | — | Name of the state, used wherever it is read or written. |
| `default` | no | string | — | Initial value, as JSON. Text needs JSON quotes, for example `"open"`. |

### `<handler>`

Declares a server Lua function the workspace can call: `read` handlers supply panel data, `action` handlers perform writes. Omit `input` and `output` to derive the contract from the typed Lua function.

Used inside: `<workspace>`.

Can contain: `<input>` (optional); `<output>` (optional); `<field>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `name` | yes | string | — | Name of the Lua function, exported as `exports.<name>`. |
| `mode` | yes | `read`, `action` | — | `read` to supply panel data, `action` to perform writes. |

### `<field>` (handler restriction)

Adds an input restriction to a handler. The server enforces it on every call, including direct API calls. Use it for arguments without a visible form field.

Used inside: `<handler>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `path` | yes | string | — | Path of the handler input to restrict. |
| `required` | no | `true` | — | Set to `true` to require a value for this Lua handler input. The server enforces it on every call. |
| `min-length` | no | whole number, 0 or more | — | Minimum text length, enforced by the server and the form. |
| `max-length` | no | whole number, 0 or more | — | Maximum text length, enforced by the server and the form. |
| `minimum` | no | number | — | Lowest allowed number, inclusive, enforced by the server and the form. |
| `maximum` | no | number | — | Highest allowed number, inclusive, enforced by the server and the form. |
| `min-items` | no | whole number, 0 or more | — | Minimum number of list items, enforced by the server and the form. |
| `max-items` | no | whole number, 0 or more | — | Maximum number of list items, enforced by the server and the form. |

### `<input>` (handler input schema)

An explicit handler input schema, using a schema root in urn:cococo:json-schema:1 or legacy JSON text/CDATA. Prefer typed Lua inputs; if you use this, supply an output schema too.

Used inside: `<handler>`.

Accepts text content.

### `<output>`

An explicit handler output schema, using a schema root in urn:cococo:json-schema:1 or legacy JSON text/CDATA. Supply it together with an input schema, or not at all.

Used inside: `<handler>`.

Accepts text content.

### `<row>`

Places its children side by side. Each child's `weight` sets its share of the width.

Used inside: `<workspace>`, `<row>`, `<column>` (layout), `<master-detail>`, `<detail>`.

Can contain: `<row>` or `<column>` or `<master-detail>` or `<panel>` or `<metric-panel>` or `<record-browser>` or `<record-editor>` or `<related-records>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `weight` | no | positive number | — | Share of the space relative to sibling layout elements. |

### `<column>` (layout)

Stacks its children vertically. Each child's `weight` sets its share of the space.

Used inside: `<workspace>`, `<row>`, `<column>` (layout), `<master-detail>`, `<detail>`.

Can contain: `<row>` or `<column>` or `<master-detail>` or `<panel>` or `<metric-panel>` or `<record-browser>` or `<record-editor>` or `<related-records>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `weight` | no | positive number | — | Share of the space relative to sibling layout elements. |

### `<master-detail>`

A two-region layout, typically a list of records on one side and the selected record on the other.

Used inside: `<workspace>`, `<row>`, `<column>` (layout), `<master-detail>`, `<detail>`.

Can contain: `<row>` or `<column>` or `<master-detail>` or `<panel>` or `<metric-panel>` or `<record-browser>` or `<record-editor>` or `<related-records>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `weight` | no | positive number | — | Share of the space relative to sibling layout elements. |

- Needs exactly two layout children.

### `<panel>`

A titled region that runs one query and displays the result with the blocks inside it. Most workspace content lives in panels.

Used inside: `<workspace>`, `<row>`, `<column>` (layout), `<master-detail>`, `<detail>`.

Can contain: `<query>` (exactly one); `<pager>` or `<filter>` or `<record-list>` or `<record-detail>` or `<record-table>` or `<kpi-summary>` or `<trend>` or `<text>` or `<form>` or `<action-form>` or generic `<block>` elements (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | yes | string | — | Heading shown to users. |
| `weight` | no | positive number | — | Share of the space relative to sibling layout elements. |
| `wait-for` | no | string | — | Space-separated query variable names that must have a value before the panel loads. An empty value loads immediately; leaving it out waits until every top-level variable has a value. |

### `<query>` (GraphQL)

Loads a panel's data with a GraphQL query written inside the element; CDATA keeps it readable. Arguments pass declared state to the query's variables.

Used inside: `<data-source>`, `<panel>`, `<record-browser>`, `<record-editor>`, `<related-records>`.

Can contain: `<arg>` (any number).

Accepts text content.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `type` | yes | `graphql` | — | Always `graphql` for this query. |

### `<query>` (Lua)

Loads a panel's data by calling a declared `read` handler in the workspace's server Lua.

Used inside: `<data-source>`, `<panel>`, `<record-browser>`, `<record-editor>`, `<related-records>`.

Can contain: `<arg>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `type` | yes | `lua` | — | Always `lua` for this query. |
| `handler` | yes | string | — | Name of a handler declared in this workspace. |

### `<query>` (MagicQuery)

Loads a panel's data with a MagicQuery: a supported noun plus named parameters, which the server expands into GraphQL.

Used inside: `<data-source>`, `<panel>`, `<record-browser>`, `<record-editor>`, `<related-records>`.

Can contain: `<arg>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `type` | yes | `magicquery` | — | Always `magicquery` for this query. |
| `noun` | yes | string | — | The MagicQuery noun to load, as listed by `listMagicQueries`. |
| `identifier` | no | string | — | Identifier of a single record to load, written literally. |
| `identifier-state` | no | string | — | State key holding the identifier of a single record to load. |

- Use `identifier` or `identifier-state`, not both.

### `<arg>` (state argument)

Passes declared workspace state to a query variable, handler input or mutation input.

Used inside: `<query>` (GraphQL), `<query>` (Lua), `<input>` (legacy mutation input), `<action-form>`, `<submit>` (legacy GraphQL), `<submit>` (legacy Lua).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `name` | yes | string | — | Name of the query variable or input that receives the value. |
| `state` | yes | string | — | State key to read. |

### `<arg>` (MagicQuery argument)

Passes one MagicQuery parameter, either from declared state or as a literal value.

Used inside: `<query>` (MagicQuery).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `name` | yes | string | — | MagicQuery parameter name. |
| `state` | no | string | — | State key supplying the value. |
| `value` | no | string | — | A literal value, as text. |

- Supply exactly one of `state` or `value`.

### `<metric-panel>`

A ready-made dashboard panel: loads a metric's recent samples and shows the statistics you choose above a trend chart.

Used inside: `<workspace>`, `<row>`, `<column>` (layout), `<master-detail>`, `<detail>`.

Can contain: `<metric>` (one or more).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | yes | string | — | Heading shown to users. |
| `metric-state` | yes | string | — | State key holding the ID of the metric to load. |
| `unit` | no | string | — | Unit shown after the value, such as `kg`. Use `unit` or `t:unit`, not both. |
| `samples` | no | whole number, 2 to 1000 | `24` | Number of recent samples to load. |
| `style` | no | `line`, `area` | `area` | Chart style. |
| `weight` | no | positive number | — | Share of the space relative to sibling layout elements. |

### `<metric>` (metric panel)

One statistic shown by a `metric-panel`, such as the average or maximum of the series.

Used inside: `<metric-panel>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `label` | yes | string | — | Label shown to users. |
| `stat` | yes | `avg`, `min`, `max`, `count` | — | The statistic to show: average, minimum, maximum or count. |

### `<record-browser>`

A ready-made list-and-detail workflow: a selectable list of records plus a detail region for the selected one. It creates its selection state if you have not declared it.

Used inside: `<workspace>`, `<row>`, `<column>` (layout), `<master-detail>`, `<detail>`.

Can contain: `<query>` (exactly one); `<detail>` (exactly one).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | yes | string | — | Heading shown to users. |
| `select` | yes | string | — | State key that holds the selected record's identity. |
| `items` | yes | string | — | Path to the list of records in the query result. |
| `as` | yes | string | — | Name for each item, used to start item paths such as `customer.node.name`. |
| `key` | yes | string | — | Path to each item's stable identity, starting with the item name. |
| `primary` | yes | string | — | Path to each item's main label, starting with the item name. |
| `secondary` | no | string | — | Path to each item's secondary label, starting with the item name. |
| `weight` | no | positive number | — | Share of the space relative to sibling layout elements. |

- It creates a list panel and a list with the IDs `<id>-list-panel` and `<id>-list`; keep every ID in the workspace unique.
- Changing the selection keeps any unsaved form drafts.
- Its query decides filtering and pagination; the component adds no search or paging controls. Add a `filter` and a `pager` alongside it for those.

### `<detail>`

The region of a `record-browser` that shows the selected record. Its contents read the selection through state.

Used inside: `<record-browser>`.

Can contain: `<row>` or `<column>` or `<master-detail>` or `<panel>` or `<metric-panel>` or `<record-browser>` or `<record-editor>` or `<related-records>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `weight` | no | positive number | `2` | Share of the space relative to sibling layout elements. |

### `<record-editor>`

A ready-made edit panel: loads the selected record and shows an edit form whose identity input is filled in automatically.

Used inside: `<workspace>`, `<row>`, `<column>` (layout), `<master-detail>`, `<detail>`.

Can contain: `<query>` (exactly one); `<submit>` (exactly one); `<section>` (any number); `<fieldset>` (any number); `<variant>` (any number); `<field>` (any number); `<value>` (any number); `<form-actions>` (exactly one).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | yes | string | — | Heading shown to users. |
| `select` | yes | string | — | State key that holds the selected record's identity. |
| `argument` | no | string | `id` | Query variable or handler input that receives the selected identity. |
| `record` | yes | string | — | Path to the record being edited in the panel's data. |
| `identity` | yes | string | — | Path to the record's identity within that record. |
| `identity-input` | no | string | `id` | Mutation or handler input that receives the record's identity automatically. |
| `weight` | no | positive number | — | Share of the space relative to sibling layout elements. |

- Its query must be GraphQL or Lua. The `argument` variable is filled from `select`; do not supply it again.
- Its form gets the ID `<id>-form`. `identity-input` is filled from `identity`; do not declare that input again.
- Submitting, validation, refresh and switching records behave as they do for `form`.

### `<related-records>`

Shows the records that belong to the selected parent, such as a customer's contacts, in a table, with an optional form for adding one. The parent's identity is filled into that form automatically.

Used inside: `<workspace>`, `<row>`, `<column>` (layout), `<master-detail>`, `<detail>`.

Can contain: `<query>` (exactly one); `<column>` (one or more); `<form>` (optional).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | yes | string | — | Heading shown to users. |
| `parent-state` | yes | string | — | State key that identifies the parent record. |
| `parent-argument` | no | string | `id` | Query variable or handler input that receives the parent's identity. |
| `parent-input` | no | string | — | Form input that receives the parent's identity. Required when a form is present. |
| `items` | yes | string | — | Path to the list of records in the query result. |
| `as` | yes | string | — | Name for each item, used to start item paths such as `customer.node.name`. |
| `weight` | no | positive number | — | Share of the space relative to sibling layout elements. |

- Its query must be GraphQL or Lua. The `parent-argument` variable is filled from `parent-state`; do not supply it again.
- Its table gets the ID `<id>-table`. When a form is present, `parent-input` is required and is filled in as a hidden value. The form must use create mode and must not supply that input again.
- After a successful save, panels refresh as usual. It does not delete records, and it does not group writes into one transaction.

### `<pager>`

Next, Previous and First buttons for a panel whose query pages through results with a cursor.

Used inside: `<panel>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `panel` | yes | string | — | ID of the panel whose results are paged. |
| `state` | yes | string | — | State key holding the cursor that the panel's query reads. |
| `next` | yes | string | — | Path in the panel's result to the end cursor of the current page. |
| `has-next` | yes | string | — | Path in the panel's result to the flag that says another page exists. |

### `<filter>`

An editable filter bound to shared state. Apply or Clear updates the state and reloads the panels that depend on it; it never submits a form.

Used inside: `<panel>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `state` | yes | string | — | State key the filter edits. |
| `label` | yes | string | — | Label shown to users. |
| `control` | no | `text`, `date`, `number` | `text` | Input control: text, date or number. |
| `placeholder` | no | string | — | Hint text shown in the empty input. |
| `empty` | no | `null`, `string` | `null` | Value stored when the filter is empty: `null`, or an empty string. |
| `reset-state` | no | string | — | Space-separated state keys set to null whenever this filter is applied or cleared, such as a pagination cursor. |

### `<record-list>`

A selectable list of records. Selecting one writes its key to shared state for other panels to use.

Used inside: `<panel>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | no | string | — | Heading shown to users. |
| `t:for` | yes | string | — | Path to the list of records in the query result. |
| `t:as` | yes | string | — | Name for each item, used to start item paths such as `customer.node.name`. |
| `primary` | yes | string | — | Path to each item's main label, starting with the item name. |
| `secondary` | no | string | — | Path to each item's secondary label, starting with the item name. |
| `select` | yes | string | — | State key that holds the selected record's identity. |
| `key` | yes | string | — | Path to each item's stable identity, starting with the item name. |

### `<record-detail>`

Shows one record: a heading plus labelled values.

Used inside: `<panel>`.

Can contain: `<field>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | no | string | — | Heading shown to users. |
| `t:text` | yes | string | — | Path to the text to show. |

### `<field>` (record detail)

One labelled value in a `record-detail`.

Used inside: `<record-detail>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `label` | yes | string | — | Label shown to users. |
| `t:value` | yes | string | — | Path to the value to show. Inside a list, start it with the item name. |

### `<record-table>`

Shows records as rows, with the columns you define.

Used inside: `<panel>`.

Can contain: `<column>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | no | string | — | Heading shown to users. |
| `t:for` | yes | string | — | Path to the list of records in the query result. |
| `t:as` | yes | string | — | Name for each item, used to start item paths such as `customer.node.name`. |

### `<column>` (table column)

One column of a table, bound to a value on each row.

Used inside: `<related-records>`, `<record-table>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `label` | yes | string | — | Label shown to users. |
| `t:value` | yes | string | — | Path to the value to show. Inside a list, start it with the item name. |
| `format` | no | `status` | — | Set to `status` to show the value as a coloured status. |

### `<kpi-summary>`

A group of headline numbers, each with a label and an optional unit and trend.

Used inside: `<panel>`.

Can contain: `<metric>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | no | string | — | Heading shown to users. |
| `layout` | no | `row`, `grid`, `list` | `row` | How the metrics are arranged. |
| `size` | no | `large`, `standard` | `large` | Size of the metric tiles. |

### `<metric>` (KPI summary)

One headline number in a `kpi-summary`.

Used inside: `<kpi-summary>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `label` | yes | string | — | Label shown to users. |
| `t:value` | yes | string | — | Path to the value to show. Inside a list, start it with the item name. |
| `unit` | no | string | — | Unit shown after the value, such as `kg`. Use `unit` or `t:unit`, not both. |
| `t:unit` | no | string | — | Path in the panel's data to the unit shown after the value. Use `unit` or `t:unit`, not both. |
| `trend` | no | string | — | Path to a trend value shown with the metric. |

### `<trend>`

A line or area chart of a series of values from the panel's data.

Used inside: `<panel>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | no | string | — | Heading shown to users. |
| `t:for` | yes | string | — | Path to the list of records in the query result. |
| `t:as` | yes | string | — | Name for each item, used to start item paths such as `customer.node.name`. |
| `t:value` | yes | string | — | Path to the value to show. Inside a list, start it with the item name. |
| `style` | no | `line`, `area` | `area` | Chart style. |

### `<text>`

Shows text, either written in the element or bound to a value in the panel's data.

Used inside: `<panel>`.

Accepts text content.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | no | string | — | Heading shown to users. |
| `t:text` | no | string | — | Path to the text to show. Leave it out to show the element's own text. |

### `<form>`

A form for creating or editing a record. It keeps the user's draft, validates it, asks for confirmation and submits it through a GraphQL mutation or a Lua action.

Used inside: `<panel>`, `<related-records>`.

Can contain: `<submit>` (exactly one); `<section>` (any number); `<fieldset>` (any number); `<variant>` (any number); `<field>` (any number); `<value>` (any number); `<form-actions>` (exactly one).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | no | string | — | Heading shown to users. |
| `record` | no | string | — | Path to the record being edited in the panel's data. |
| `identity` | no | string | — | Path to the record's identity within that record. |
| `mode` | no | `create`, `edit` | — | `create` or `edit`. Defaults to edit when `record` is set. |

- `mode` defaults to edit when `record` is set, otherwise create. Edit mode needs `record` and `identity`.
- For GraphQL, inputs and response selections are checked against your instance schema. For Lua, inputs come from the declared handler.

### `<submit>` (form)

How a form submits: a GraphQL mutation written inside the element, or a server Lua action. It also says where to find errors and the saved record in the response.

Used inside: `<record-editor>`, `<form>`.

Accepts text content.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `type` | yes | `graphql`, `lua` | — | `graphql` to run the mutation written inside the element, `lua` to call an action handler. |
| `handler` | no | string | — | Name of a handler declared in this workspace. |
| `result` | no | string | — | Path in the response to the saved record, used to confirm what was saved. |
| `errors` | yes | string | — | Path in the response to the list of structured errors. |
| `error-prefix` | no | string | — | Prefix added to server error paths before they are matched to form inputs. |
| `confirm` | no | string | — | Confirmation message shown before submitting. Defaults to the workspace title followed by `: confirm change`. Leaving it out does not skip confirmation. |

- A GraphQL submit contains a mutation and no `handler`. A Lua submit names an action handler and contains no text.
- `errors` must point to a structured error list. `result`, when given, must contain every field the form reads from the record.

### `<variant>`

Lets the user choose one of several shapes for part of the input, for example a person or a company, each with its own fields.

Used inside: `<record-editor>`, `<form>`, `<case>`, `<fieldset>` (variant case), `<section>` (variant case), `<fieldset>` (form).

Can contain: `<case>` (one or more).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `path` | yes | string | — | Path of the input object the variant fills. |
| `encoding` | yes | `one-of`, `discriminator` | — | How the choice is sent: `one-of` for a GraphQL OneOf input, `discriminator` for an input with a type field. |
| `label` | yes | string | — | Label shown above the choice of cases. |
| `discriminator` | no | string | — | The input member that records the chosen case. Required for discriminator encoding. |
| `source` | no | string | — | Path in the edited record that supplies the initial value. |
| `state` | no | string | — | Workspace state key whose value fills this input. Editing the form does not change that state. |
| `submit` | no | `always`, `changed` | `always` | `always` sends the value every time; `changed` sends it only when the user changed it. |
| `default-case` | no | string | — | Case selected initially for new records. Never overrides the case of an existing record. |

- With `one-of` encoding, the input must be a GraphQL OneOf object and every member needs a case. Cases that are single values or lists are not supported. Use `field` on each case, never `value`.
- The variant fills its whole input and submits exactly one selected member. Required fields of a case must appear in that case.
- With `discriminator` encoding, the discriminator must be a direct string or enum input, and each case uses `value`, never `field`. Enum and Lua choices need a case for every value. Required fields shared by every case must be declared in each case.
- For Lua inputs, each alternative must be a closed object with one common required discriminator and unique string values.
- Case fields are relative to the selected object. Cases that reuse a field name keep separate drafts.
- Cases can contain conditional fieldsets, nested variants, static options and lookups. Fields and variants keep the order you write them in.

### `<case>`

One choice within a `variant`, with the fields that belong to it.

Used inside: `<variant>`.

Can contain: `<field>` (any number); `<variant>` (any number); `<fieldset>` (any number); `<section>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `field` | no | string | — | The GraphQL OneOf member this case fills. Required for one-of encoding. |
| `value` | no | string | — | The discriminator value this case sends. Required for discriminator encoding. |
| `label` | yes | string | — | Label shown for this case. |

### `<fieldset>` (variant case)

A conditional group of fields inside a variant case. Its `when` condition decides whether the fields take part; hidden drafts are kept.

Used inside: `<case>`, `<fieldset>` (variant case), `<section>` (variant case).

Can contain: `<field>` (any number); `<variant>` (any number); `<fieldset>` (any number); `<section>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | no | string | — | Heading shown to users. |
| `columns` | no | `1`, `2` | `1` | Number of columns. |
| `when` | no | string | — | A condition in the `form-predicate/1` language that decides whether this group takes part (see Conditional forms). It reads form input and variant selections, never workspace state. |

- Field paths are relative to the case, but `when` conditions use the full input path, including the member name for OneOf cases.
- `selection[variant-id]` can refer to the containing variant, its ancestors, and variants outside the group it controls. Its value is the selected case key, or null.
- A required field can be hidden only if it belongs to an optional object whose fields are all hidden together.
- Drafts in hidden groups are kept, but they are not validated or submitted.
- Conditions can read fields at the top of the form and in the containing cases, but not fields in sibling conditional groups.

### `<section>` (variant case)

A plain group of fields inside a variant case, laid out in one or two columns.

Used inside: `<case>`, `<fieldset>` (variant case), `<section>` (variant case).

Can contain: `<field>` (any number); `<variant>` (any number); `<fieldset>` (any number); `<section>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `title` | yes | string | — | Heading shown to users. |
| `columns` | no | `1`, `2` | `1` | Number of columns. |

### `<field>` (variant case)

An input inside a variant case. Its path is relative to the selected case.

Used inside: `<case>`, `<fieldset>` (variant case), `<section>` (variant case).

Can contain: `<option>` (any number); `<lookup>` (optional).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `path` | yes | string | — | Path of this input, relative to the selected case. |
| `source` | no | string | — | Path in the edited record that supplies the initial value. |
| `label` | no | string | — | Label shown to users. |
| `control` | no | `text`, `textarea`, `email`, `phone`, `password`, `number`, `toggle`, `select`, `record-picker`, `json` | — | Input control to show. By default it is chosen from the input's type. |
| `placeholder` | no | string | — | Hint text shown in the empty input. |
| `help` | no | string | — | Short explanation shown with the input. Defaults to the schema's description when there is one. |
| `readonly` | no | `true`, `false` | `false` | Set to `true` to show the value without letting the user change it. |

### `<fieldset>` (form)

A conditional group of fields. Its `when` condition decides whether they are validated and submitted; hidden drafts are kept, not cleared.

Used inside: `<record-editor>`, `<form>`, `<fieldset>` (form).

Can contain: `<field>` (any number); `<value>` (any number); `<section>` (any number); `<fieldset>` (any number); `<variant>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | no | string | — | Heading shown to users. |
| `columns` | no | `1`, `2` | `1` | Number of columns. |
| `when` | no | string | — | A condition in the `form-predicate/1` language that decides whether this group takes part (see Conditional forms). It reads form input and variant selections, never workspace state. |

- Needs a version of the CoCoCo app that supports conditional forms. Hidden fields keep their drafts but are not validated or submitted.
- At most 64 groups and 8 levels of nesting; IDs are unique within the form.
- Conditions can read fields that are always shown or belong to an enclosing group, and variant selections, but never their own contents or unrelated conditional groups. `selection[variant-id]` is the selected case key, or null; switching case re-evaluates dependent fieldsets.
- A required field can be hidden only when its whole optional object is left out. Field paths stay absolute.
- Contains fields, values, sections and nested fieldsets. Inside a variant case, use the variant-case fieldset.

### `<section>` (form)

A plain group of fields, laid out in one or two columns.

Used inside: `<record-editor>`, `<form>`, `<fieldset>` (form).

Can contain: `<field>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `title` | yes | string | — | Heading shown to users. |
| `columns` | no | `1`, `2` | `1` | Number of columns. |

### `<field>` (form field)

A visible input in a form, bound to one path in the mutation or handler input.

Used inside: `<record-editor>`, `<form>`, `<fieldset>` (form), `<section>` (form).

Can contain: `<option>` (any number); `<lookup>` (optional).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `path` | yes | string | — | Path of this input in the mutation variables or handler input. |
| `label` | no | string | — | Label shown to users. |
| `source` | no | string | — | Path in the edited record that supplies the initial value. |
| `state` | no | string | — | Workspace state key whose value fills this input. Editing the form does not change that state. |
| `control` | no | `text`, `textarea`, `email`, `phone`, `password`, `number`, `toggle`, `select`, `record-picker`, `json` | — | Input control to show. By default it is chosen from the input's type. |
| `placeholder` | no | string | — | Hint text shown in the empty input. |
| `help` | no | string | — | Short explanation shown with the input. Defaults to the schema's description when there is one. |
| `submit` | no | `always`, `changed` | `always` | `always` sends the value every time; `changed` sends it only when the user changed it. |
| `readonly` | no | `true`, `false` | `false` | Set to `true` to show the value without letting the user change it. |
| `required` | no | `true` | — | Set to `true` to require a value for this Lua handler input. The server enforces it on every call. |
| `min-length` | no | whole number, 0 or more | — | Minimum text length, enforced by the server and the form. |
| `max-length` | no | whole number, 0 or more | — | Maximum text length, enforced by the server and the form. |
| `minimum` | no | number | — | Lowest allowed number, inclusive, enforced by the server and the form. |
| `maximum` | no | number | — | Highest allowed number, inclusive, enforced by the server and the form. |
| `min-items` | no | whole number, 0 or more | — | Minimum number of list items, enforced by the server and the form. |
| `max-items` | no | whole number, 0 or more | — | Maximum number of list items, enforced by the server and the form. |

- Use `source` or `state`, not both, and either `lookup` or `option` children, not both.
- The control defaults from the input's type; a `lookup` makes it a record picker. Required inputs must use `submit="always"`.

### `<value>`

A hidden, read-only input in a form, such as a record ID taken from the record or from state.

Used inside: `<record-editor>`, `<form>`, `<fieldset>` (form).

Can contain: `<option>` (any number); `<lookup>` (optional).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `path` | yes | string | — | Path of this input in the mutation variables or handler input. |
| `label` | no | string | — | Label shown to users. |
| `source` | no | string | — | Path in the edited record that supplies the initial value. |
| `state` | no | string | — | Workspace state key whose value fills this input. Editing the form does not change that state. |
| `control` | no | `text`, `textarea`, `email`, `phone`, `password`, `number`, `toggle`, `select`, `record-picker`, `json` | — | Input control to show. By default it is chosen from the input's type. |
| `placeholder` | no | string | — | Hint text shown in the empty input. |
| `help` | no | string | — | Short explanation shown with the input. Defaults to the schema's description when there is one. |
| `submit` | no | `always`, `changed` | `always` | `always` sends the value every time; `changed` sends it only when the user changed it. |
| `readonly` | no | `true`, `false` | `false` | Set to `true` to show the value without letting the user change it. |

- Use `source` or `state`, not both, and either `lookup` or `option` children, not both.
- Required inputs must use `submit="always"`.

### `<option>`

One fixed choice for a field, with a label and a JSON value.

Used inside: `<field>` (variant case), `<field>` (form field), `<value>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `label` | yes | string | — | Label shown to users. |
| `value` | yes | string | — | The value stored when this option is chosen, as JSON. |

### `<lookup>`

Offers a field's choices from the records another panel or data source has loaded. Searching filters only those loaded records.

Used inside: `<field>` (variant case), `<field>` (form field), `<value>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `panel` | yes | string | — | ID of the panel or data source whose records supply the choices. |
| `items` | yes | string | — | Path to the list of records in that panel's result. |
| `value` | yes | string | — | Path, relative to each record, to the value stored when it is chosen. Do not start it with an item name. |
| `label` | yes | string | — | Path, relative to each record, to the label shown for it. Do not start it with an item name. |

### `<form-actions>`

Sets the text of a form's save and reset buttons.

Used inside: `<record-editor>`, `<form>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `save-label` | no | string | `Save` | Text of the save button. |
| `reset-label` | no | string | `Discard changes` | Text of the button that discards changes. |

## Legacy components

These remain supported for existing workspaces. Use `form` for new work: it protects the user's draft.

### `<input>` (legacy mutation input)

Groups nested input values for a legacy GraphQL submit.

Used inside: `<input>` (legacy mutation input), `<submit>` (legacy GraphQL).

Can contain: `<arg>` (any number); `<input>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `name` | yes | string | — | Name of the nested input object. |

### `<action-form>`

A legacy form that writes shared state and runs an action. Use `form` instead: it protects the user's draft.

Used inside: `<panel>`.

Can contain: `<field>` (any number); `<arg>` (any number); `<submit>` (optional).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `id` | yes | string | — | Unique identifier: lowercase letters, digits and hyphens, starting with a letter. |
| `title` | no | string | — | Heading shown to users. |
| `handler` | no | string | — | Name of a handler declared in this workspace. |
| `label` | yes | string | — | Label shown to users. |
| `confirm` | yes | string | — | Confirmation message shown before submitting. Defaults to the workspace title followed by `: confirm change`. Leaving it out does not skip confirmation. |
| `success` | no | string | — | Message shown after the action succeeds. |

### `<field>` (legacy)

An input in a legacy `action-form`.

Used inside: `<action-form>`.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `state` | yes | string | — | State key the input writes. |
| `label` | yes | string | — | Label shown to users. |
| `type` | no | string | — | Input type. |
| `placeholder` | no | string | — | Hint text shown in the empty input. |

### `<submit>` (legacy GraphQL)

The GraphQL mutation a legacy `action-form` runs.

Used inside: `<action-form>`.

Can contain: `<arg>` (any number); `<input>` (any number).

Accepts text content.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `type` | yes | `graphql` | — | Always `graphql` for this submit. |

### `<submit>` (legacy Lua)

The Lua action a legacy `action-form` runs.

Used inside: `<action-form>`.

Can contain: `<arg>` (any number).

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `type` | yes | `lua` | — | Always `lua` for this submit. |
| `handler` | yes | string | — | Name of a handler declared in this workspace. |

## Advanced: generic blocks

A generic `<block type="…">` places any block the CoCoCo app can display directly in a panel, for cases the components above do not cover. Prefer the components above: they add checks and behavior that generic blocks lack.

Settings go in an optional `<config>` child, and bindings to the panel's data in an optional `<data-binding>` child; each binding is literal text or a `{{ dot.path }}` expression. Values an attribute cannot express, such as lists and objects, go in `<property>` children. Do not set the same property twice; the server checks each block type's other rules when you save.

Every generic block needs `type` and `id`. Most also accept these common attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `aiHint` | no | string | — | Context for the AI assistant about what this block shows. |
| `id` | yes | string | — | Unique identifier for the block. |
| `subtitle` | no | string | — | Secondary text shown under the title. |
| `title` | no | string | — | Heading shown above the block. |
| `visibilityCondition` | no | string | — | A `{{ }}` expression over the panel's data. The block is shown only when it is true. |

### `<property>`

Sets one property of a generic block, or of its `config` or `data-binding`, to a JSON value. Use it for values an attribute cannot express, such as lists and objects.

Accepts text content.

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `name` | yes | string | — | Name of the property to set. |

### `ActionGroup`

A row or column of action buttons.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `layout` | no | `row`, `column` | — | Arrange the buttons in a `row` or a `column`. |

### `AiInsight`

An AI analysis of the panel's data, shown inline. It runs when the panel loads or refreshes, is read-only, and is advisory. It needs a configured AI assistant.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `focus` | no | string | — | Optional topic to focus the analysis on, such as "delivery risk". |
| `scope` | no | `panel` | — | What to analyse. Currently always the panel the block is in. |

### `AlertBlock`

A message with a severity: info, warning, error or critical.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `severity` | no | `info`, `warning`, `error`, `critical` | — | How serious the message is; sets its colour. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `actionLabel` | no | string | — | Label for an action on the alert. The CoCoCo app does not show it yet. |
| `message` | no | string | — | The message text. |

### `Checklist`

A list of items with a done state, such as the steps of a process.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `showIcons` | no | `true`, `false` | — | Set to `true` to show check icons. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `items` | no | string | — | The list of items. |
| `label` | no | string | — | Each item's label. |
| `state` | no | string | — | Each item's state; a done-like value shows a tick. |

### `DataList`

A list of rows with a main line, a second line, a badge and a status dot. `record-list` covers the common case.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `isSelectable` | no | `true`, `false` | — | Set to `true` to let users select rows. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `badge` | no | string | — | Badge text on each row. |
| `items` | no | string | — | The list of rows. |
| `primaryText` | no | string | — | Main line of each row. |
| `secondaryText` | no | string | — | Second line of each row. |
| `statusDot` | no | string | — | Each row's status, shown as a coloured dot. |

### `DataTable`

A table of rows. `record-table` covers the common case.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `isSortable` | no | `true`, `false` | — | Set to `true` to let users sort by column. |
| `pagination` | no | `true`, `false` | — | Set to `true` to split long tables into pages. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `rows` | no | string | — | The list of rows. |

### `FilterBar`

A row of filter options the user can choose from.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `multiSelect` | no | `true`, `false` | — | Set to `true` to allow more than one selection. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `options` | no | string | — | The list of options. |
| `value` | no | string | — | The selected value or values. |

### `Form`

The low-level form block. Use `form` instead, which adds draft protection and schema checks.

Common attributes: `id`, `subtitle`, `title`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `conditionProfile` | no | `form-predicate/1` | — | Condition language used by conditional groups. Always `form-predicate/1`. |
| `errorPrefix` | no | string | — | Prefix added to server error paths before they are matched to inputs. |
| `errors` | no | string | — | Path in the response to the list of structured errors. |
| `identity` | no | string | — | Path to the record's identity within the record. |
| `mode` | no | `create`, `edit` | — | `create` or `edit`. |
| `mutationId` | no | string | — | ID of the mutation the form submits. |
| `record` | no | string | — | Path to the record being edited in the panel's data. |
| `resetLabel` | no | string | — | Text of the button that discards changes. |
| `result` | no | string | — | Path in the response to the saved record. |
| `submitLabel` | no | string | — | Text of the submit button. |

### `FormBlock`

Input fields that write workspace state for a following action. Prefer `form`.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

### `GaugeChart`

A gauge showing one number between a minimum and a maximum.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `max` | no | number | — | Highest value on the gauge. |
| `min` | no | number | — | Lowest value on the gauge. |
| `thickness` | no | `thick`, `thin` | — | Thickness of the gauge ring. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `label` | no | string | — | Label shown with the gauge. |
| `value` | no | string | — | The number to show. |

### `Journey`

Embeds a published Journey, a guided step-by-step process, in the panel.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `handle` | no | string | — | Handle of the published journey to embed. Write it literally; it cannot be bound to data. |

### `MapBlock`

A map with a marker for each location.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `defaultZoom` | no | number | — | Initial zoom level. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `label` | no | string | — | Each marker's label. |
| `lat` | no | string | — | Each location's latitude. |
| `lng` | no | string | — | Each location's longitude. |
| `locations` | no | string | — | The list of locations. |

### `MediaPreview`

An image preview, with text shown when there is no image.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `aspectRatio` | no | string | — | Aspect ratio of the preview area. |
| `objectFit` | no | string | — | How the image fills the preview area. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `fallbackText` | no | string | — | Text shown when there is no image. |
| `thumbnailUrl` | no | string | — | Address of the image. |

### `MetricGroup`

A group of metric tiles. `kpi-summary` covers the common case.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `layout` | no | `row`, `grid`, `list` | — | How the metric tiles are arranged. |
| `size` | no | `large`, `standard` | — | Size of the metric tiles. |

### `Pager`

Next, Previous and First buttons. `pager` covers the common case.

Common attributes: `id`, `title`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `hasNext` | no | string | — | Path in the panel's result to the flag that says another page exists. |
| `next` | no | string | — | Path in the panel's result to the end cursor of the current page. |
| `panel` | no | string | — | ID of the panel whose results are paged. |
| `state` | no | string | — | State key holding the cursor that the panel's query reads. |

### `ProgressBar`

A progress bar with optional labels at each end.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `color` | no | string | — | Colour of the bar. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `labelLeft` | no | string | — | Label at the left end. |
| `labelRight` | no | string | — | Label at the right end. |
| `percentage` | no | string | — | Progress, from 0 to 100. |

### `RecordCard`

A card showing one record, with a title, a status badge and labelled fields. `record-detail` covers the common case.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `layout` | no | string | — | Layout of the card. |
| `showAvatar` | no | `true`, `false` | — | Set to `true` to show an avatar. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `statusBadge` | no | string | — | The record's status, shown as a badge. |
| `title` | no | string | — | The record's title. |

### `RelationGraph`

A diagram of records and the links between them.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `layout` | no | string | — | How the diagram is arranged. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `edges` | no | string | — | The list of links between them. |
| `nodes` | no | string | — | The list of records to draw. |

### `SparklineChart`

A small line or area chart. `trend` covers the common case.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `color` | no | string | — | Colour of the line. |
| `type` | no | `line`, `area` | — | `line` or `area`. |
| `valueKey` | no | string | — | When each point is an object, the path to its number. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `dataPoints` | no | string | — | The list of numbers, or of objects (see `valueKey`). |

### `StateInput`

An input bound to workspace state. `filter` covers the common case.

Common attributes: `id`, `title`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `control` | no | `text`, `date`, `number` | — | Input control: text, date or number. |
| `empty` | no | `null`, `string` | — | Value stored when the input is empty: `null`, or an empty string. |
| `label` | no | string | — | Label shown to users. |
| `placeholder` | no | string | — | Hint text shown in the empty input. |
| `state` | no | string | — | State key the input edits. |

### `SwatchSet`

A set of colour swatches, each with a label.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `shape` | no | `circle`, `square` | — | `circle` or `square`. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `colorCode` | no | string | — | Each swatch's colour code. |
| `label` | no | string | — | Each swatch's label. |
| `swatches` | no | string | — | The list of swatches. |

### `TabSwitch`

A row of tabs the user can switch between. Define the tabs with a `<property name="tabs">` list of labels and values.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

### `Text`

Text, optionally formatted as Markdown. `text` covers the common case.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<config>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `markdown` | no | `true`, `false` | — | Set to `true` to format the text as Markdown. |
| `style` | no | `title`, `heading`, `body`, `caption` | — | Text style: title, heading, body or caption. |

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `text` | no | string | — | The text to show. |

### `Timeline`

A vertical timeline of events.

Common attributes: `aiHint`, `id`, `subtitle`, `title`, `visibilityCondition`.

`<data-binding>` attributes:

| Attribute | Required | Values / type | Default | Meaning |
|---|---|---|---|---|
| `detail` | no | string | — | Each event's detail text. |
| `items` | no | string | — | The list of events. |
| `statusDot` | no | string | — | Each event's status, shown as a coloured marker. |
| `timestamp` | no | string | — | Each event's time. |
| `title` | no | string | — | Each event's title. |