Skip to content

Form tokens

The dashboard renders forms from JSON Schema. A role’s form_schema (and a workflow’s inputSchema) declares structure: properties, types, required, title, description, and x-lt-* tokens. The renderer supplies layout, styling, validation and accessibility. This page covers how a schema becomes controls; each token family has its own page.

The control follows the field’s declared type and its tokens; a stored value only fills it. A field with no value renders its control’s empty state: an empty number input, an unchecked box, a select opened on Choose…, a multi-select with nothing picked, an empty JSON editor. Every property starts at its default, or {} for an object, or empty text.

Declared type Renders as
boolean Checkbox
boolean + enum or x-lt-options Select emitting true or false (a yes or no decision)
number / integer Number input
string Text input; format: "textarea" for multi-line
string / number + enum Select
Any scalar + x-lt-options Select with labeled options: inline, from the context, or from a lookup (see Validation and options)
array + x-lt-options Multi-select chips emitting the picked values in list order
array / object + x-lt-widget: "json" Validated JSON editor (see Widgets)
array without options Tag display (read-only)
object Nested fields from properties, or a widget (see Widgets)
null Read-only “null” display

format on a string field selects a specialized input:

Format Renders as
"password" Masked input. An ephemeral token replaces the value in the resolver payload
"date" Date picker
"date-time" Date and time picker
"email" Email input; a pre-submission check enforces a valid address
"uri" URL input; a pre-submission check enforces https?://...
"textarea" Multi-line text area
{
"properties": {
"due_date": { "type": "string", "format": "date" },
"contact_email": { "type": "string", "format": "email" },
"report_url": { "type": "string", "format": "uri" },
"notes": { "type": "string", "format": "textarea" }
}
}

A field’s label resolves in order:

  1. The title keyword, the author’s explicit label. It always wins.
  2. Snake and kebab keys, title-cased: item_count becomes Item Count. All-caps tokens inside a key keep their casing: po_number becomes Po Number, PO_number becomes PO Number.
  3. Single-token keys pass through unchanged: PO, SKU, ITEMCOUNT.

Declare title on every field whose key is not already a readable label. The label appears everywhere the field faces a person: the form, the dictionary display and the errors panel.

{
"properties": {
"ITEMCOUNT": { "type": "number", "title": "Item count" }
}
}

title and description at the schema root render in the form header: title as the section header, description as a short subtitle beneath it. Keep the description to a phrase; longer guidance belongs in x-lt-help. A field’s own title and description render as its label and its inline instruction.

{
"title": "Expense approval",
"description": "Review the expense report and approve or reject with notes.",
"properties": {
"approved": {
"type": "boolean",
"title": "Approve",
"description": "Check to approve. Leave unchecked to reject."
}
}
}

Every required input (text, select, number, upload or checklist group) shows a red asterisk at its label and blocks submission when empty. A checklist with x-lt-require-all is required by definition and carries the asterisk too.

{
"required": ["decision"],
"properties": {
"decision": { "type": "string", "enum": ["approve", "reject"] },
"notes": { "type": "string", "description": "Optional comments" }
}
}

A required object field (a checklist widget, for example) is satisfied when at least one of its boolean values is true. Fields hidden by x-lt-showIf at submit time skip required validation (see Conditional visibility).

readOnly: true displays the value as static text:

{
"properties": {
"request_amount": { "type": "number", "readOnly": true },
"approved_amount": { "type": "number", "description": "Enter the approved amount" }
}
}

Pair readOnly with x-lt-hide-if-empty: true to suppress empty facts, with x-lt-display: "dictionary" to render facts as a definition list, or with x-lt-widget: "markdown" to embed a rendered content block such as review instructions.

"format": "password" fields are masked. On submit, the platform replaces the plain-text value with a short-lived ephemeral token (eph:v1:*, 15-minute TTL) before storing it or signaling the workflow, so the secret stays out of the escalation record. The workflow receives the token and passes it to the integration layer for redemption.

{
"required": ["api_key", "api_secret"],
"properties": {
"api_key": { "type": "string", "description": "API key" },
"api_secret": {
"type": "string",
"format": "password",
"description": "API secret, stored as an ephemeral token"
}
}
}

The renderer applies one set of rules to every generated form:

  • Width follows content. Forms hold a readable measure, selects size to their options, numbers stay hand-sized, and prose fields fill their cell.
  • Decisions are enums. A decision field renders as a select that opens on a disabled Choose… placeholder, so the resolver makes an explicit pick. Model decisions as enum.
  • Checkboxes confirm work and live in checklists. Sentence-length require-all items render one per row; short pick-any tags flow as chips. The renderer chooses from item length and x-lt-require-all; x-lt-variant overrides.
  • Geometry follows the container. Dictionaries reflow from paired columns to stacked labels as space narrows, tables fold into cards, and the form grid drops to one column when the side panel narrows it.

A form that resolves quickly follows one shape: facts first as a dictionary, one explicit decision that gates the rest, each outcome revealing its own section with x-lt-showIf, pairs side by side with x-lt-column-group, and a short sign-off note last.

At the field. The first failing check on a visible field renders inline: the border takes the error color, the field shakes once, and the message appears beneath the control. Format checks fire on blur; everything else fires on submit.

The errors panel. A blocked submit opens the side panel with every issue: the field’s label and the message. Clicking a row scrolls to and focuses the field. The count (“3 issues to resolve”) updates as fixes land.

Server enforcement. Roles with enforce_schema validate the submission on the server and reject an invalid payload with a canonical 422 carrying per-field errors. The form maps those onto the same inline and panel surfaces, so the resolver sees one error language wherever the check ran. See Schema enforcement.

Write custom messages as the instruction the resolver should follow, in one line: “Enter a quantity between 1 and 4.”

Form edits save to browser storage, per escalation, a moment after each change, and restore when the resolver returns to the item. A lapsed claim, an accidental navigation or a browser restart keeps typed input. The draft holds field values only; the form always renders from the current schema. Untouched defaults are not stored. The draft clears when the escalation is resolved, acknowledged or cancelled from that browser.

  • Every input is associated with its label (label[for] to input[id]), and checkbox labels wrap their controls.
  • Required fields set aria-required; failing fields set aria-invalid and link their message through aria-describedby.
  • Inline messages and the errors panel render as role="alert" live regions, so corrections are announced as they happen.
  • The checklist widget is a role="group" labeled by its field description.
  • A locked form (unclaimed, claimed by another user, or a lapsed claim) is inert: its fields leave the tab order.
  • Modals are role="dialog" with aria-modal and a labeled title; Escape closes them.
  • Entries in the errors panel are buttons: activating one focuses the failing field, by keyboard too.
Token Placement Purpose
x-lt-layout Root "two-column" grid; on a list schema, the page layout
x-lt-span Field 2 spans the full width of a two-column grid
x-lt-order Root Explicit field order
x-lt-section Field Groups fields under a labeled section
x-lt-column-group Field Pairs consecutive fields inside one grid cell
x-lt-bind Field The path the value occupies in the payload
x-lt-help Root Markdown guidance in the side panel, with {{domain.path}} tokens
x-lt-context Root Plain-text guidance when x-lt-help is absent
x-lt-showIf Field Show the field when a condition holds
x-lt-hide-if-empty Field Suppress the field when its value is empty
x-lt-hidden Field Never render; the value passes through
x-lt-widget Field A rich input or display block in place of the default control
x-lt-language Field Syntax hint for the code-editor widget
x-lt-source Field The path holding checklist items, or the embedded escalation id
x-lt-default-checked Field An unanswered checklist starts fully checked
x-lt-variant Field Checklist shape: rows or chips
x-lt-display Field or root "dictionary" renders read-only facts as a definition list
x-lt-section-options Root Per-section display and column settings
x-lt-scan Field The scan schemes a field accepts and the values it expects
x-lt-scan-submit Root Submit once every required scan field holds a value
x-lt-min-length / x-lt-max-length Field String length bounds read from a path at submit
x-lt-minimum / x-lt-maximum Field Numeric bounds read from a path at submit
x-lt-pattern-error Field Custom message when pattern fails
x-lt-options Field Select options: literal, from a path, or from a lookup; cascades
x-lt-nullable Field A select can be cleared back to null
x-lt-require-all Field Every checklist item must be checked
x-lt-require-any Root At least one field of a group holds a value
x-lt-require-sum Root A group of numeric fields reaches a minimum total
x-lt-labels Root Rename the footer actions; cancel: false removes cancel
x-lt-submit-on-claim Root Claiming also submits the form
x-lt-transition Root Wait screen until the next step is assigned to the submitter
x-lt-transition-message Root Markdown on the wait screen
x-lt-transition-max-wait-seconds Root How long the wait screen waits (5 to 300, default 30)
x-lt-transition-done Root Where the page goes when the step ends
x-lt-href Field URL template for the link widget
x-lt-fields Field Facts on an embedded escalation card
x-lt-query Field Facet query for the escalation-list widget
x-lt-columns Field or list schema Columns for an escalation list, roster or facet table
x-lt-actions Field Inline row actions on an escalation list or roster
x-lt-submit-guard Root Hold submit while a query or roster has outstanding rows
x-lt-invoke Field Start a workflow from the form, directly or through its form
x-lt-roster Field Expected members of a container, each waiting, in or flagged
x-lt-active / x-lt-history List schema The live item card and the history column
x-lt-group-by List schema Board entity key, or table row grouping
x-lt-related List schema Named related sets beside each row
x-lt-row-detail List schema Sections in a row expansion
x-lt-card List schema The card on a facet board
x-lt-row-action List schema The row click: claim or view
x-lt-viewport Root Replace the form with your own app in an iframe

Invoke forms covers the same vocabulary on a workflow’s inputSchema.