Skip to main content

Fields

The fields property defines how each form field is displayed and behaves. Each key must match a property name in your schema.

Field Definition

{
"fields": {
"fieldName": {
"label": "Display Label",
"description": "Help text",
"placeholder": "Placeholder text",
"type": "text",
"visibleWhen": "...",
"requiredWhen": "...",
"enabledWhen": "...",
"validations": [...],
"options": [...]
}
}
}

Common Properties

PropertyTypeDescription
labelstringDisplay label shown above the field
descriptionstringHelp text shown below the field
placeholderstringPlaceholder text inside the input
typestringField type override (see Field Types)
defaultValueanyInitial value when form loads (must match type)
readonlyWhenFEELExpressionWhen this field is read-only
variantstringPresentation variant (see Variants)
variantConfigRecord<string, unknown>Variant-specific configuration

Default Values

Use defaultValue to pre-populate a field when the form loads:

{
"country": {
"label": "Country",
"type": "select",
"defaultValue": "us",
"options": [
{ "value": "us", "label": "United States" },
{ "value": "ca", "label": "Canada" }
]
},
"quantity": {
"label": "Quantity",
"type": "integer",
"defaultValue": 1
},
"subscribe": {
"label": "Subscribe to newsletter",
"type": "boolean",
"defaultValue": true
}
}

Resolution order (highest priority wins):

  1. initialData prop passed at runtime
  2. defaultValue from the field definition
  3. Implicit type defaults (booleans default to false)

Notes:

  • defaultValue must match the field's schema type (string for text/select, number for number/integer, boolean for boolean)
  • Display fields cannot have defaultValue
  • For array item fields, defaultValue is applied each time a new item is added

Field Types

The type property determines how the field is rendered. If omitted, it's inferred from the schema.

Text Input Types

TypeDescriptionSchema Type
textSingle-line text inputstring
textareaMulti-line text inputstring
emailEmail input with validationstring (format: email)
urlURL inputstring (format: uri)
passwordPassword input (masked)string
phonePhone number inputstring
{
"bio": {
"label": "Biography",
"type": "textarea",
"placeholder": "Tell us about yourself..."
}
}

Phone Fields

Use type: "phone" for phone number inputs. This renders an HTML tel input, which triggers the phone keyboard on mobile devices.

Basic phone — simple phone collection without a country picker:

{
"phone": {
"type": "phone",
"label": "Phone Number",
"placeholder": "(555) 555-5555"
}
}

International phone — with country code picker, flag icons, and auto-formatting. Uses the phone-international variant and stores values in E.164 format (+12015550123):

{
"phone": {
"type": "phone",
"label": "Phone Number",
"variant": "phone-international",
"variantConfig": {
"defaultCountry": "us"
}
}
}

The international variant requires format: "phone" in the schema to enforce E.164 validation:

{
"schema": {
"properties": {
"phone": { "type": "string", "format": "phone" }
}
}
}
ScenarioVariantSchema Format
Simple phone collection(none)string (no format)
International with country pickerphone-internationalstring with format: "phone"
Phone with specific regex(none)string + FEEL matches() validation
tip

Only add format: "phone" when using the phone-international variant. For basic phone fields, use plain type: "string" — the format constraint enforces strict E.164, which users won't type manually without a country picker.

Numeric Types

TypeDescriptionSchema Type
numberDecimal number inputnumber
integerWhole number inputinteger
{
"quantity": {
"label": "Quantity",
"type": "integer",
"description": "Enter a whole number"
}
}

Boolean Type

TypeDescriptionSchema Type
booleanCheckbox or toggleboolean
{
"subscribe": {
"label": "Subscribe to newsletter",
"type": "boolean"
}
}

Date Types

TypeDescriptionSchema Type
dateDate pickerstring (format: date)
datetimeDate and time pickerstring (format: date-time)
{
"appointmentDate": {
"label": "Preferred Date",
"type": "date"
}
}

Selection Types

TypeDescriptionSchema Type
selectDropdown selectionstring with enum
multiselectMultiple selectionarray of strings
{
"country": {
"label": "Country",
"type": "select",
"options": [
{ "value": "us", "label": "United States" },
{ "value": "ca", "label": "Canada" },
{ "value": "uk", "label": "United Kingdom" }
]
}
}

Matrix Type

TypeDescriptionSchema Type
matrixGrid of rows × columns (e.g. Likert scale)object
{
"service_rating": {
"label": "Rate our service",
"type": "matrix",
"rows": [
{ "id": "speed", "label": "Speed" },
{ "id": "quality", "label": "Quality" },
{ "id": "support", "label": "Support" }
],
"columns": [
{ "value": 1, "label": "Poor" },
{ "value": 2, "label": "Fair" },
{ "value": 3, "label": "Good" },
{ "value": 4, "label": "Excellent" }
]
}
}

For full details, see Matrix Fields below.

Complex Types

TypeDescriptionSchema Type
arrayRepeatable group of fieldsarray
objectNested field groupobject
computedRead-only calculated valueN/A
displayRead-only display contentN/A

Display Fields

Display fields show read-only content such as headings, metrics, or alerts. They have no user input and are not included in form data.

{
"header": {
"type": "display",
"label": "Section Header",
"content": "Please review the following information."
},
"totalDisplay": {
"type": "display",
"label": "Order Total",
"source": "total",
"format": "currency"
}
}
PropertyTypeDescription
contentstring | undefinedStatic text content
sourcestring | undefinedComputed field name to display dynamically
formatstring | undefinedDisplay format hint (e.g., "currency")

For rendering details, see Display Fields in the forma-react docs.

Options

For select and multiselect fields, define available choices:

{
"options": [
{ "value": "option1", "label": "Option One" },
{ "value": "option2", "label": "Option Two" }
]
}

Option Properties

PropertyTypeDescription
valuestring | numberValue stored when selected
labelstringDisplay text shown to user
visibleWhenstringFEEL expression to conditionally show option

Conditional Options

Show options based on other field values:

{
"plan": {
"label": "Plan",
"type": "select",
"options": [
{ "value": "free", "label": "Free" },
{ "value": "pro", "label": "Pro" },
{
"value": "enterprise",
"label": "Enterprise",
"visibleWhen": "companySize > 100"
}
]
}
}

Array Fields

For repeatable groups of fields, use type: "array" with itemFields:

{
"schema": {
"properties": {
"contacts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string" }
}
}
}
}
},
"fields": {
"contacts": {
"label": "Contacts",
"type": "array",
"minItems": 1,
"maxItems": 5,
"itemFields": {
"name": { "label": "Name" },
"email": { "label": "Email" }
}
}
}
}

Array Properties

PropertyTypeDescription
itemFieldsobjectField definitions for each array item
minItemsintegerMinimum required items
maxItemsintegerMaximum allowed items

Object Fields

For nested data structures, use type: "object". Object fields group nested properties defined in the schema — unlike array fields, they do not use itemFields:

{
"schema": {
"properties": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"zipCode": { "type": "string" }
}
}
}
},
"fields": {
"address": {
"label": "Address",
"type": "object"
},
"address.street": { "label": "Street" },
"address.city": { "label": "City" },
"address.zipCode": { "label": "ZIP Code" }
},
"fieldOrder": ["address"]
}

Access nested values in expressions with dot notation: address.city, address.zipCode.

Matrix Fields

Matrix fields render a grid where users select one (or more) options per row. Common uses include Likert scales, satisfaction surveys, and rating grids.

Field Definition

{
"service_rating": {
"label": "Rate our service",
"type": "matrix",
"rows": [
{ "id": "speed", "label": "Speed of service" },
{ "id": "quality", "label": "Quality of work" },
{ "id": "support", "label": "Customer support" }
],
"columns": [
{ "value": 1, "label": "Poor" },
{ "value": 2, "label": "Fair" },
{ "value": 3, "label": "Good" },
{ "value": 4, "label": "Excellent" }
]
}
}

Properties

PropertyTypeRequiredDescription
rowsMatrixRow[]YesRow definitions (items/statements to rate)
columnsMatrixColumn[]YesColumn definitions (shared response options)
multiSelectbooleanNoAllow multiple selections per row (default: false)

MatrixRow:

PropertyTypeRequiredDescription
idstringYesUnique identifier (snake_case, used in data keys and FEEL)
labelstringYesDisplay label
visibleWhenstringNoFEEL expression to conditionally show the row

MatrixColumn:

PropertyTypeRequiredDescription
valuestring | numberYesValue stored when selected
labelstringYesDisplay label

Data Shape

Single-select (default): each row stores one value.

{ "speed": 4, "quality": 3, "support": 4 }

Multi-select (multiSelect: true): each row stores an array of values.

{ "speed": [3, 4], "quality": [4], "support": [2, 3] }

Schema

The corresponding JSON Schema uses type: "object" with one property per row. Each property has an enum matching the column values:

{
"schema": {
"properties": {
"service_rating": {
"type": "object",
"properties": {
"speed": { "type": "integer", "enum": [1, 2, 3, 4] },
"quality": { "type": "integer", "enum": [1, 2, 3, 4] },
"support": { "type": "integer", "enum": [1, 2, 3, 4] }
},
"required": ["speed", "quality", "support"]
}
}
}
}

For multi-select matrices, each row property is an array of the enum type instead.

Categorical Columns

Use string values for non-numeric scales:

{
"columns": [
{ "value": "strongly_disagree", "label": "Strongly Disagree" },
{ "value": "disagree", "label": "Disagree" },
{ "value": "neutral", "label": "Neutral" },
{ "value": "agree", "label": "Agree" },
{ "value": "strongly_agree", "label": "Strongly Agree" }
]
}
warning

Do not use string representations of numbers (e.g. "4") as column values. FEEL functions like mean() return null on strings. Use actual numbers (4) for numeric scales.

FEEL Access

Access matrix values using dot notation — fieldId.rowId:

{
"visibleWhen": "service_rating.speed >= 3",
"rule": "service_rating.quality >= 2",
"expression": "mean([service_rating.speed, service_rating.quality, service_rating.support])"
}

Conditional Rows

Show or hide individual rows based on form state:

{
"rows": [
{ "id": "speed", "label": "Speed" },
{ "id": "quality", "label": "Quality" },
{
"id": "support",
"label": "Customer Support",
"visibleWhen": "used_support = true"
}
]
}

Field Order

The fieldOrder array determines the display order:

{
"fieldOrder": ["firstName", "lastName", "email", "phone"]
}

Fields not in fieldOrder are not displayed.

Presentation Variants

The variant property lets a single field type render as different UI components. For example, a number field can appear as a slider, a stepper, or an NPS scale without changing the field type.

Available Variants

Field TypeVariantDescriptionvariantConfig Keys
numbersliderRange slidershowValue (boolean)
numberstepperIncrement/decrement buttons
numbernps0–10 NPS scalelowLabel, highLabel
numberrating-starsStar ratingmaxStars (default 5)
numberrating-numericNumeric rating buttonsmaxRating (default 5)
phonephone-internationalCountry picker with E.164defaultCountry (ISO alpha-2, default "us")
selectradioRadio button group
selectradio-cardsCard-style radio options
selectbutton-groupSegmented button group
displayheadingSection headinglevel (2–5)
displaydividerVisual separator
displaymetricLarge numeric displayunit
displayalertAlert with severityseverity ("info", "warning", "error", "success")
displaycalloutInformational callouticon (e.g., "info", "lightbulb")
displaysummaryCard-based summary
matrixlikertLikert scale layout
matrixdropdown-gridDropdowns per row

Example

{
"fields": {
"satisfaction": {
"type": "number",
"label": "How likely are you to recommend us?",
"variant": "nps",
"variantConfig": {
"lowLabel": "Not at all likely",
"highLabel": "Extremely likely"
}
}
}
}

For implementation details on rendering variants in React, see Presentation Variants in the forma-react docs.

Type Inference

In the TypeScript type system, type is a required property on FieldDefinition. At runtime, if type is omitted, it can be inferred from the schema:

SchemaInferred Type
{ "type": "string" }text
{ "type": "string", "format": "email" }email
{ "type": "string", "format": "phone" }phone
{ "type": "string", "format": "date" }date
{ "type": "string", "enum": [...] }select
{ "type": "integer" }integer
{ "type": "number" }number
{ "type": "boolean" }boolean
{ "type": "array" }array
{ "type": "object" } (with matrix field def)matrix