Skip to content

Form schema API reference

Team Forms stores each form layout as a Form.io compatible JSON schema. This reference covers the supported authoring surface used by the Team Forms builder and AI assistant.

The builder may retain additional Form.io defaults and internal properties. When editing source JSON, preserve properties you do not understand and add only properties that are relevant to the required behaviour.

The schema has the following top-level properties:

PropertyTypeDescription
display"form" | "wizard"Selects a standard single-page form or a multi-page wizard.
componentscomponent arrayContains the form’s top-level components. Wizard schemas contain one top-level panel for each page.
settingsobject, optionalStores form-level renderer settings. Preserve existing settings unless you are changing a documented form-level option.

The form title, icon, custom CSS, PDF options, response-title template, and published state are form configuration rather than component schema properties.

{
"display": "form",
"components": [
{
"type": "textfield",
"key": "requesterName",
"label": "Requester name",
"validate": {
"required": true
}
},
{
"type": "button",
"key": "submit",
"label": "Submit",
"action": "submit",
"disableOnInvalid": false
}
]
}

Every component requires a supported type and a unique, descriptive camel-case key. Most input components also require a concise label. Only include optional properties when they change the component’s behaviour.

PropertyTypeDescription
typestringThe exact component type from the component catalogue below.
keystringUnique camel-case identifier used in response data and JavaScript, such as requesterName. It must also satisfy the reserved-name rules below.
labelstringUser-facing caption for an input. Panels use title for their visible heading.
titlestringVisible heading for a panel, including a wizard page.
descriptionstringSupporting text displayed with the component.
tooltipstringAdditional guidance displayed on demand.
placeholderstringExample or hint displayed inside an empty input.
prefixstringContent displayed before the input value.
suffixstringContent displayed after the input value.
customClassstringStatic CSS class names added to the component. Do not include a leading dot.
defaultValueanyStatic value used when the component has no response value. The value must match the component’s data shape.
multiplebooleanAllows multiple values where the component supports it.
hiddenbooleanHides the component while retaining it in the schema.
disabledbooleanPrevents the user from changing the value.
clearOnHidebooleanClears the stored value when the component becomes hidden.
persistentboolean or stringControls whether the value is included in saved response data. Use the builder defaults unless there is a specific requirement.
protectedbooleanMarks response data as protected. Do not enable it without a specific requirement.
uniquebooleanRequests uniqueness validation for the value. Do not assume it replaces workflow or server-side uniqueness guarantees.
tableViewbooleanControls whether the field is included in default response tables.
inputbooleanIdentifies a value-producing component. Layout and content components normally set this to false; input components normally inherit true.
modalEditbooleanOpens editing in a modal where supported. Prefer the normal inline experience unless requested.
autofocusbooleanFocuses the component when the form opens. Only one component should normally use this.
redrawOnstringComponent key whose changes should redraw this component. Use "data" to redraw for any response-data change.
refreshOnstringComponent key whose changes should refresh a component’s data.
validateOn"change" | "blur"Selects when validation runs.
validateobjectContains validation rules described below.
errorLabelstringAlternate name used in validation messages.
pdfVisibility"visible" | "hidden" | "hideIfEmpty"Controls whether the component is rendered in generated PDFs. This is independent of browser-form visibility.

The builder calls key the component’s Property Name. It is used in response data, Handlebars paths, executable JavaScript, email suggestions, and connector schemas, so changing it after responses exist can break those references.

A key must:

  • contain only letters, numbers, underscores, dots, and dashes;
  • start and end with a letter, number, or underscore;
  • be unique and preferably use descriptive camelCase; and
  • not equal a registered component type, case-insensitively, unless it is the current component’s own type.

The reserved names are the component type values in this reference, including names such as textfield, email, select, content, panel, columns, datagrid, file, spSelect, and approval.

ComponentKeyValidReason
textfieldrequesterEmailYesDescriptive and not a component type.
emailemailYesA component may use its own type as its key.
textfieldemailNoemail is another registered component type.
numberdataGridNoReserved-name comparison is case-insensitive, so it conflicts with datagrid.
textfieldrequester nameNoSpaces are not allowed.

For generated forms, prefer domain-specific keys instead of generic component names even where the own-type exception would allow them.

PropertyApplies toDescription
validate.requiredmost inputsRequires a non-empty response.
validate.minLengthtext inputsMinimum number of characters.
validate.maxLengthtext inputsMaximum number of characters.
validate.minWordstext areasMinimum word count.
validate.maxWordstext areasMaximum word count.
validate.minnumber, currency, date/timeMinimum accepted value.
validate.maxnumber, currency, date/timeMaximum accepted value.
validate.patterntext inputsRegular-expression pattern the value must match.
validate.customadvancedJavaScript that assigns a boolean or message to valid. Use the exact development context supplied by the AI assistant.
validate.uniquesupported inputsRequests a unique value. Confirm that the intended storage and submission path supports this behaviour.
TypeUseImportant properties
textfieldShort general-purpose text.Common text properties and validate.
textareaMulti-line or long text.rows, autoExpand, editor, and text validation. Use a plain textarea unless rich text is requested.
emailEmail address.Built-in email validation plus common text properties. Prefer this over textfield for email.
urlWeb address.Built-in URL validation plus common text properties.
phoneNumberTelephone number.Common text properties and an input mask configured through the builder when needed.
numberNumeric input.delimiter, decimalLimit, requireDecimal, and validate.min or validate.max.
currencyMonetary value.currency, decimalLimit, delimiter, and numeric validation.
TypeUseImportant properties
checkboxOne boolean choice.defaultValue is normally true or false.
radioOne choice displayed as radio options.values, inline, and defaultValue.
selectboxesMultiple choices displayed as checkboxes.values, inline, and defaultValue.
selectDrop-down or searchable choice.dataSrc, data, valueProperty, template, multiple, and refreshOn.
tagsFree-form or suggested tags.storeas, delimiter, and maxTags.
surveySeveral related questions sharing one response scale.questions and values.

Radio and select-box options use values:

{
"type": "radio",
"key": "priority",
"label": "Priority",
"values": [
{ "label": "Low", "value": "low" },
{ "label": "Medium", "value": "medium" },
{ "label": "High", "value": "high" }
]
}

A static drop-down uses dataSrc: "values" and data.values:

{
"type": "select",
"key": "department",
"label": "Department",
"dataSrc": "values",
"data": {
"values": [
{ "label": "Finance", "value": "finance" },
{ "label": "Operations", "value": "operations" }
]
}
}

A survey contains stable values for both its questions and response scale:

{
"type": "survey",
"key": "serviceRatings",
"label": "Service ratings",
"questions": [
{ "label": "Response time", "value": "responseTime" },
{ "label": "Communication", "value": "communication" }
],
"values": [
{ "label": "Poor", "value": "poor" },
{ "label": "Good", "value": "good" },
{ "label": "Excellent", "value": "excellent" }
]
}
TypeUseImportant properties
datetimeDate-only, time-only, or combined date/time input.enableDate, enableTime, defaultToCurrentDate, defaultDate, format, datePicker, and timePicker.
timeTime-only input.inputType, format, and common input properties.

Use datetime with enableTime: false for a date-only field. To default it to today, set both defaultToCurrentDate: true and defaultDate: "moment().format()".

{
"type": "datetime",
"key": "requestDate",
"label": "Request date",
"enableTime": false,
"defaultToCurrentDate": true,
"defaultDate": "moment().format()"
}

The older day component can appear in existing schemas, but datetime with enableTime: false is preferred for new forms.

TypeUseImportant properties
addressStructured address lookup.provider and enableManualMode. Preserve provider-specific configuration from the builder.
userMicrosoft 365 user picker.usersSource is "teamMembers", "organization", or "specificUsers"; it may also use specificUsers, selectFields, sampleItem, refreshOn, and clearOnCopy. The AI assistant normally uses "organization" and must never invent directory users.
signatureDrawn or typed signature.enableTyping; set it to true for newly generated signatures.
fileFile or image upload.storage, multiple, fileTypes, fileMaxSize, showImageEditor, and webcam. Team Forms uploads use storage: "indexeddb"; do not enable webcam automatically.
sketchPadMark up a predefined image.file contains the background image. Use an existing or placeholder image rather than inventing base64 image data.
locationSelect or capture a map location.map.defaultCenterSource, map.showResetLocationButton, map.height, map.zoom, and map controls.
barcodeScannerScan a barcode or QR code with the device camera.Common input properties; the stored value contains the scanned value and format.
submissionNumberDisplay the form’s sequential submission number.padding controls leading zeros. This value is assigned during submission and cannot be relied on by live calculated fields.
hiddenStore data without displaying an input.defaultValue, calculateValue, customDefaultValue, and persistence settings.
spSelectSelect an object from an existing Team Forms data source.dataSourceId, template, labelProperty, selectFields, removeDuplicates, sortBy, sortDirection, and filterQuery. Pair a directly supplied custom template with labelProperty: { "label": "🛠 Custom", "value": "custom" }. Never set valueProperty.
approvalAdd an approval step that may contain approver fields.components, exact approvers, chooseApprover, revokers, dependsOn, and action-specific email wrappers. Do not add approvalStatus manually.

Example Team Forms user picker:

{
"type": "user",
"key": "lineManager",
"label": "Line manager",
"usersSource": "organization"
}

Example image upload:

{
"type": "file",
"key": "supportingImages",
"label": "Supporting images",
"storage": "indexeddb",
"multiple": true,
"showImageEditor": true,
"webcam": false
}

See User component schema for user sources, projections, and stored directory objects. See Data-source component schema for the exact spSelect projection and duplicate-removal order, source-type mapping, filters, and sharepointFilePreview. See Approval component schema for exact approver objects, dependencies, conditional approvals, stored status, submit behaviour, and notification templates.

TypeUseImportant properties and child shape
contentRich explanatory content.html contains the markup and input is false. Inline <svg> markup is not supported by the Form.io renderer; use an <img> whose src is an embedded data:image/svg+xml URI instead.
htmlelementBasic HTML element in existing schemas.tag, content, attrs, and input: false. Prefer content for rich instructions.
panelTitled visual section or wizard page.title, components, collapsible, collapsed, and scrollToTop.
wellVisually grouped child components.components.
fieldsetSemantically grouped child components.legend or label, plus components.
tabsTabbed groups.components contains tab objects, each with label, key, and components.
columnsResponsive horizontal layout.Each column uses size: "md" (xs, sm, md, lg, or xl), numeric width and currentWidth values from 1–12, and components. Widths in a row must total 12.
tableFixed rows and columns used for layout.rows contains arrays of cells; each cell has components.
pdfPageBreakStarts a new page in generated PDF output.Normally input: false. It does not create a browser-form page.
sharepointFilePreviewDisplays an existing SharePoint file preview while online.dataSourceId, height (minimum 200), input: false, and pdfVisibility: "hidden". The source type must be sharepoint-file-preview.

Example two-column layout:

{
"type": "columns",
"key": "requesterDetails",
"label": "Requester details",
"columns": [
{
"size": "md",
"width": 6,
"currentWidth": 6,
"components": []
},
{
"size": "md",
"width": 6,
"currentWidth": 6,
"components": []
}
]
}
TypeUseImportant properties and data shape
containerGroups children and nests their response data under the container key.components. Use a panel or fieldset when nesting response data is not required.
datagridRepeatable rows with a fixed set of child fields.components, initEmpty, reorder, addAnother, responsiveLayout, responsiveBreakpoint, and row validation. Calculations inside a row can read row.
datamapUser-defined key/value pairs.valueComponent defines the value editor. Use sparingly; a datagrid is usually clearer.

Set responsiveLayout: true on new data grids so each row stacks vertically on smaller screens. responsiveBreakpoint controls when this happens and supports sm, md, or lg; use md unless another breakpoint is specifically required.

See Nested and repeating component schema for exact response paths, row calculations, fixed rows, containers, Data Maps, and Handlebars iteration.

editgrid and tree can appear in existing advanced forms. They have more complex editing and nested-data behaviour and should not be generated or reconfigured without explicit requirements and relevant existing schema context.

Every supported visual component can control its generated-PDF visibility independently from its browser-form visibility:

pdfVisibilityBehaviour
visibleAllow the component to render in the PDF. Normal conditional logic still applies. This is the default.
hiddenNever render the component in the PDF.
hideIfEmptyRender the component only when it or its child components contain a value.

The static hidden property controls browser-form visibility and does not imply that the component is hidden in the PDF. For example, a calculated summary can be hidden from the browser form but deliberately included in the PDF:

{
"type": "content",
"key": "pdfSummary",
"html": "<p>Submitted by {{ data.requesterName }}</p>",
"hidden": true,
"pdfVisibility": "visible",
"input": false
}

Use pdfVisibility: "hidden" for browser-only instructions, interactive controls, or online previews. Use hideIfEmpty for optional questions or sections that should not leave blank space in the generated document. Conditional rules such as conditional and customConditional continue to be evaluated in PDF rendering.

TypeUseImportant properties
buttonSubmit or custom action.action, theme, disableOnInvalid, event, and onChange. Standard forms end with action: "submit"; wizard navigation supplies the final submit action. Team Forms hides normal submit actions while a visible approval supplies its own actions.

Each top-level wizard component is a panel representing a page. Set scrollToTop: true on each page. Do not add a submit button to the last page because the wizard renderer supplies its own navigation and final submit action.

{
"display": "wizard",
"components": [
{
"type": "panel",
"key": "requestDetailsPage",
"title": "Request details",
"scrollToTop": true,
"components": []
},
{
"type": "panel",
"key": "reviewPage",
"title": "Review",
"scrollToTop": true,
"components": []
}
]
}

Executable properties contain JavaScript statements evaluated by Form.io and Team Forms. Property names and mutable output variables are exact. Do not derive them from the labels displayed by the builder.

Builder settingSchema propertyRequired outputBehaviour
Calculated ValuecalculateValuevalueRecalculates the component value when relevant form data changes. Never use calculatedValue; that is not the schema setting.
Custom Default ValuecustomDefaultValuevalueComputes the initial value without continually overwriting later user input.
Custom ConditionalcustomConditionalshowShows or hides the component by assigning a boolean.
Dynamically DisabledcustomDisableddisabledEnables or disables the component by assigning a boolean.
Custom Validationvalidate.customvalidAssigns true, false, or a validation message.
Change handleronChangenoneRuns after the component value changes. Use only when a calculated or conditional property is not suitable.
Dynamic custom classcustomClassAdvancedcustomClassComputes CSS class names. Static class names belong in customClass.
Custom select datadata.customvaluesComputes or loads a select’s available options.
JavaScript logic triggerlogic.trigger.javascriptresultDetermines whether a logic trigger runs.
Logic value actionlogic.actions.valuevalueComputes the value assigned by a logic action.
Logic schema actionlogic.actions.schemaDefinitionschemaComputes a schema fragment applied by a logic action.

Calculated value example:

{
"type": "number",
"key": "lineTotal",
"label": "Line total",
"calculateValue": "value = (Number(data.quantity) || 0) * (Number(data.unitPrice) || 0)"
}

Inside a datagrid row, use row for values in that row:

{
"type": "number",
"key": "lineTotal",
"label": "Line total",
"calculateValue": "value = (Number(row.quantity) || 0) * (Number(row.unitPrice) || 0)"
}

Conditional visibility example:

{
"type": "textarea",
"key": "rejectionReason",
"label": "Rejection reason",
"customConditional": "show = data.decision === 'rejected'"
}

Executable schema values contain JavaScript statements, not a wrapping function and not TypeScript. When using the AI assistant, it loads the available Team Forms and Form.io declarations for the exact component and schema property before changing executable code.

Labels and content can interpolate response data with expressions such as {{ data.requesterName }}. They do not evaluate arbitrary JavaScript. Set redrawOn to the referenced component key, or to "data" when any response change should refresh the content.

{
"type": "content",
"key": "requestSummary",
"html": "<p>Request for {{ data.requesterName }}</p>",
"redrawOn": "requesterName",
"input": false
}

The following component types can appear in Team Forms but depend on advanced product state. Preserve them when editing existing forms. Do not invent their configuration without the required context.

TypeContext required
recaptchaPublished-form and provider configuration.
passwordA specific requirement for masked text and an understood persistence policy.
editgridExplicit row-editing requirements and existing nested schema context.
treeExplicit recursive data requirements and existing nested schema context.