Skip to content

Widgets

Set x-lt-widget on a field to render a rich input or a display block in place of the control its type would get.

Widget What it renders
file-upload File picker with drag and drop. Stores a base64 data URL. accept filters file types
code-editor Monospace textarea with tab-key support. x-lt-language names the syntax
json Validated JSON editor for a list or object field. Text that does not parse reads Invalid JSON and holds the submit; a parsed value validates as the declared type
signature Canvas drawing pad. Outputs a PNG data URL
rich-text Tall textarea for formatted text
markdown Markdown source rendered with headings, tables, lists and code blocks. Editable by default; readOnly: true makes it a content block
checklist Labeled checkboxes driven by runtime data from the "domain.path" in x-lt-source
attachment Read-only display of a captured binary (data URL or fetchable URL): images inline with click to full size, everything else as an open or download link. image is an alias
link Read-only navigation link from an x-lt-href template. See x-lt-embed
escalation Read-only embedded escalation card, ID from x-lt-source, facts from x-lt-fields. See x-lt-embed
escalation-list Read-only embedded escalation list from an x-lt-query, columns from x-lt-columns. See x-lt-embed
roster Read-only list of every member a container row expects, each waiting, in, or flagged. See x-lt-roster
invoke Read-only control that starts a workflow, directly or in a prefilled dialog. See x-lt-invoke
textarea Alias of format: "textarea": a multi-line text box

A string field renders as a textarea when it declares format: "textarea" or x-lt-widget: "textarea", when its value holds a line break, or when its value runs past 80 characters. Read-only fields and dictionary displays keep the line breaks the value carries.

The link, escalation, escalation-list, invoke and roster widgets are display-only: the payload mapper drops their keys, so they contribute nothing to the submitted payload.

The escalation schema editor flags any x-lt-widget name outside this table. The schema still saves, and the field renders as its type’s default control.

{
"properties": {
"screenshot": {
"type": "string",
"x-lt-widget": "file-upload",
"accept": "image/*",
"description": "Upload a screenshot of the issue"
},
"signed_form": {
"type": "string",
"x-lt-widget": "file-upload",
"accept": ".pdf",
"description": "Signed authorization form (PDF)"
}
}
}

The submitted value is a base64 data URL (data:image/png;base64,...). accept follows the HTML <input accept> syntax.

{
"properties": {
"fix_script": {
"type": "string",
"x-lt-widget": "code-editor",
"x-lt-language": "sql",
"description": "SQL migration to apply"
}
}
}

x-lt-language is a display hint. The editor accepts any text.

{
"properties": {
"weights": {
"type": "object",
"x-lt-widget": "json",
"propertyNames": { "enum": ["small", "medium", "large"] },
"additionalProperties": { "type": "number", "minimum": 0, "maximum": 1 },
"description": "Zero or omit a key to exclude it"
}
}
}

A monospace editor holding the raw JSON of a type: "array" or "object" field. While the text fails to parse, the field reads Invalid JSON and holds the submit. Once it parses, the value validates as the declared type: items (type, enum, bounds), minItems and maxItems for lists; propertyNames.enum and additionalProperties (type, minimum, maximum) for maps. Empty text submits null. Typing leaves the text as written. See Lists and maps.

{
"properties": {
"signature": {
"type": "string",
"x-lt-widget": "signature",
"description": "Sign to confirm"
}
}
}

The submitted value is a PNG data URL of the drawing.

A read-only display of a binary captured earlier, typically by a file-upload field on a prior form. The reporting form uploads the evidence (a defect photo, a signed PDF, a scan); the review form shows it:

{
"properties": {
"defect_evidence": {
"type": "string",
"readOnly": true,
"x-lt-widget": "attachment",
"description": "Uploaded by the reporting form"
}
}
}

The value is a data URL or a fetchable URL. Rendering follows the content type: image/* renders inline (constrained, click for full size); PDFs, scans and other binaries render as a labeled open or download link. Only images embed, because the image context runs no script. image is an accepted alias when the schema wants to name that intent. An empty value reads “No attachment”.

Without readOnly, the field is a markdown editor with a Write and Preview toggle; the submitted value is the markdown text.

With readOnly: true, the field is a rendered content block. The markdown in its default displays as HTML inside the form: headings, tables, checklists, callouts. The versioned schema carries the page source, so review instructions version with the form they belong to.

{
"properties": {
"review_guide": {
"type": "string",
"readOnly": true,
"x-lt-widget": "markdown",
"x-lt-span": 2,
"default": "### Review checklist\n\n1. Confirm the **legal name** matches.\n2. Send a test message before approving.\n\n> Send non-standard contract language to legal."
}
}
}

A list of labeled checkboxes driven by runtime data in the escalation context. The item definitions come from the path in x-lt-source, so the form schema stays fixed while item count and labels vary across escalations.

The field type is "object". The submitted value is Record<string, boolean> keyed by item id, for example { "step_0": true, "step_1": false }.

{
"properties": {
"checks": {
"type": "object",
"description": "Work through each step and check it off.",
"x-lt-widget": "checklist",
"x-lt-source": "envelope.checklist_items"
}
},
"required": ["checks"]
}

x-lt-source uses the "domain.path" convention (the same as x-lt-showIf and x-lt-help tokens) and may embed {{domain.path}} interpolation segments. It is a single path or an ordered array of paths; the first that resolves to items wins, so a lookup-backed row and an envelope-embedded row render the same shared schema. The renderer reads an array of { id: string; label: string; required?: boolean } objects at the resolved path.

Domain Use it for
envelope Item definitions that are render data only, at no query cost. The workflow puts them in conditional’s envelope
lookup Item sets shared by many rows: a versioned knowledge edition, pinned or current. See Lookups
metadata Items that must be indexed and searchable as facets. Adds index cost

"x-lt-default-checked": true opens an unanswered checklist with every item checked: the submitter unchecks what failed instead of confirming what passed. The default applies once, when the source resolves. A record that already carries an answer map for the field (a reopened draft, an edited state) renders its saved state. Without the flag, items start unchecked.

The flag lives on the widget because the item set is runtime-sourced: the step that creates the escalation cannot enumerate a lookup edition’s ids to seed formDefaults. Membership and completion guards are unaffected, since the default is a subset of the resolved items.

Variant Shape Use it for
rows One item per line Sentence-length confirmations, read top-down and ticked deliberately
chips A wrapping cloud of selectable pills Short pick-any items (reject reasons, categories); a selection shows in solid accent

Set x-lt-variant explicitly, or let the renderer decide: x-lt-require-all always renders rows; otherwise chips when every label is 28 characters or fewer. The submitted value is the same in both shapes.

{
"rejectReasons": {
"type": "object",
"description": "Check every reason that applies",
"x-lt-widget": "checklist",
"x-lt-source": "envelope.reject_reason_items",
"x-lt-variant": "chips"
}
}
Level Declaration Holds the submit until
None Field absent from required Never; the items are informational
At least one Field listed in required Any one item is checked
All "x-lt-require-all": true on the field Every item is checked, except items declared required: false

An item with required: true carries an asterisk. In at-least-one mode, unchecked items highlight red after a submit attempt only while zero are checked; one check meets the group requirement and clears the highlights.

x-lt-require-all is the completion guard for station forms where every check is a confirmation. Unchecked mandatory items highlight red after a submit attempt and clear as they are checked; the error panel reads N of M checks incomplete. It composes with required (require-all is stricter and wins) and is vacuous when the source resolves to no items. See Checklist completion.

workflows/checklist.ts
const checklistItems = [
{ id: 'doc', label: 'All supporting documentation is attached', required: true },
{ id: 'contact', label: 'Contact details have been verified', required: true },
{ id: 'photos', label: 'Before and after photos are present', required: false },
];
const decision = await conditional<{ checks: Record<string, boolean> }>(signalId, {
role: 'checklist-operator',
envelope: {
checklist_items: checklistItems,
formDefaults: {
checks: Object.fromEntries(checklistItems.map((i) => [i.id, false])),
},
},
});
const allConfirmed = Object.values(decision.checks).every(Boolean);

Seeding formDefaults.checks opens the form with every checkbox unchecked rather than indeterminate. The checklist-confirmation and constraint-form example workflows in the long-tail repo are complete references.