Skip to content

Form Field Types Reference

Complete reference for all supported form field types in ApprovalML workflows.


Type Category Description
text Text Single-line text input
textarea Text Multi-line text input
email Text Email with format validation
richtext Text WYSIWYG rich text editor
markdown Text Markdown editor with live preview
number Numeric Integer or decimal input
currency Numeric Money amount with symbol
date Date & Time Calendar date picker (date only)
datetime Date & Time Date and time picker
dropdown / select Selection Single-choice dropdown
multiselect Selection Multi-choice dropdown
radio Selection Radio buttons or button group
checkbox Selection Boolean toggle
autocomplete Selection Search-as-you-type with data source
user_lookup Selection Internal employee search-as-you-type
file_upload / file File & Media File or image attachment (use accept: ".pdf" for PDF-only)
image File & Media Display-only image — Media Gallery asset, company logo, or direct URL
signature File & Media Digital signature capture
line_items Advanced Repeating row table
autonumber Advanced Sequential auto-generated number
json Advanced Structured JSON data with tree view
hidden Advanced Non-displayed metadata field

Single-line text input for short responses.

- name: employee_name
type: text
label: "Full Name"
required: true
placeholder: "Enter your full name"
min_length: 2
max_length: 100

Common Uses: Names, titles, short descriptions, IDs, reference codes


Multi-line text input for longer responses.

- name: description
type: textarea
label: "Description"
required: true
rows: 4
placeholder: "Enter detailed description..."
min_length: 10
max_length: 1000

Common Uses: Descriptions, comments, justifications, policy notes


Email address input with built-in format validation.

- name: contact_email
type: email
label: "Email Address"
required: true
placeholder: "user@company.com"

Validation: Automatically enforces user@domain.tld format.

Common Uses: Contact emails, approver addresses, notification recipients


WYSIWYG rich text editor with HTML formatting and image embedding.

- name: detailed_description
type: richtext
label: "Detailed Description"
required: false
placeholder: "Enter formatted text with images..."

Features:

  • Bold, italic, underline, heading formatting
  • Bullet lists and numbered lists
  • Hyperlinks
  • Image upload (auto-converted to base64)
  • Stored as HTML

Storage: Saved to S3 at companies/{company_id}/workflows/{workflow_id}/instances/{instance_id}/richtext/{field_name}.html

Common Uses: Policy documents, detailed proposals, formatted instructions


Markdown editor with toolbar and live preview. Values are stored as plain Markdown text.

- name: notes
type: markdown
label: "Notes"
required: false
placeholder: "Enter notes using Markdown..."
min_length: 10
max_length: 5000

Features:

  • Bold, italic, headings
  • Bullet and numbered lists
  • Hyperlinks
  • Thematic breaks
  • Live side-by-side preview
  • Stored as plain Markdown in request_data

Validation: Supports required, min_length, and max_length.

Common Uses: Structured notes, documentation, comments, changelog entries


Numeric input accepting integers or decimals.

- name: quantity
type: number
label: "Quantity"
required: true
placeholder: "0"
min_value: 1
max_value: 1000

Properties:

Property Description
min_value Minimum allowed value
max_value Maximum allowed value

Common Uses: Quantities, counts, percentages, ratings, days


Money amount with automatic currency symbol formatting.

- name: total_amount
type: currency
label: "Total Amount"
required: true
currency: "USD"
min_value: 0.01
max_value: 1000000

Properties:

Property Description Default
currency ISO 4217 currency code "USD"
min_value Minimum amount
max_value Maximum amount
readonly Prevent editing (use with formula) false
calculated Marks field as computed false
formula Expression to calculate value

Supported currencies: USD, EUR, GBP, JPY, SGD, IDR, MYR, AUD, and all ISO 4217 codes.

Common Uses: Purchase amounts, budgets, salaries, invoice totals, line-item subtotals


Calendar date picker — captures date only, no time component. Stored as YYYY-MM-DD.

- name: start_date
type: date
label: "Start Date"
required: true
min_date: "2024-01-01"
max_date: "2025-12-31"

Properties:

Property Description
min_date Earliest selectable date (YYYY-MM-DD)
max_date Latest selectable date (YYYY-MM-DD)

Common Uses: Deadlines, start/end dates, travel dates, expiry dates


Date and time picker — captures both date and time in local time. Stored as YYYY-MM-DDTHH:mm.

- name: meeting_datetime
type: datetime
label: "Meeting Date & Time"
required: true

Properties:

Property Description
min_date Earliest selectable datetime (YYYY-MM-DDTHH:mm)
max_date Latest selectable datetime (YYYY-MM-DDTHH:mm)

Display: Shown using the company date format for the date portion followed by HH:mm — e.g. 15/05/2026 14:00.

Common Uses: Meeting schedules, appointment booking, event timestamps, payment cut-off times

When to choose date vs datetime:

  • Use date when only the calendar day matters (payment date, deadline, travel date)
  • Use datetime when the time of day is relevant (meeting time, submission cut-off, event schedule)

Single-choice dropdown with predefined or dynamic options. dropdown and select are aliases — use whichever reads more naturally.

- name: department
type: dropdown
label: "Department"
required: true
options:
- label: "Engineering"
value: "engineering"
- label: "Sales"
value: "sales"
- label: "Marketing"
value: "marketing"

Common Uses: Departments, categories, statuses, priorities, countries


Multi-choice dropdown — user can select one or more options.

- name: required_skills
type: multiselect
label: "Required Skills"
required: false
options:
- label: "JavaScript"
value: "javascript"
- label: "Python"
value: "python"
- label: "Java"
value: "java"

Common Uses: Skills, tags, cost centers, systems affected, roles


Radio button group for single selection. Supports a compact button-style layout.

- name: urgency
type: radio
label: "Urgency Level"
required: true
display_as: "buttons" # Optional: renders as styled button group
options:
- label: "Low"
value: "low"
- label: "Medium"
value: "medium"
- label: "High"
value: "high"
- label: "Critical"
value: "critical"

Properties:

Property Description
display_as "buttons" for button-group style; omit for classic radio circles

Common Uses: Priority levels, approval types, yes/no, rating scales


Single boolean toggle for true/false responses.

- name: agree_to_terms
type: checkbox
label: "I agree to the terms and conditions"
required: true

Common Uses: Agreements, acknowledgements, opt-ins, feature flags


Search-as-you-type field backed by a dynamic Data Processor. Requires a configured Data Processor — static options are not supported.

- name: employee
type: autocomplete
label: "Select Employee"
required: true
options:
data_processor:
source_id: "src_employees"
value_field: "id"
label_field: "name"
display: "{name} - {department}"
search:
min_length: 2 # Start searching after 2 characters
debounce_ms: 300 # Delay before querying (default: 300ms)

Properties:

Property Description
options.data_processor.source_id Registered Data Processor ID
options.data_processor.value_field Field used as the stored value
options.data_processor.label_field Field shown in the dropdown
options.data_processor.display Template for display text (e.g. "{name} - {dept}")
search.min_length Characters required before search fires (default: 2)
search.debounce_ms Milliseconds to wait between keystrokes (default: 300)

Common Uses: Employee picker, product search, customer lookup, location select


Internal employee search-as-you-type field. Unlike autocomplete, this field uses a dedicated company-scoped people directory — no Data Processor configuration required. The stored value is a rich snapshot that remains human-readable in PDFs and approval emails without extra database queries.

- name: assessment_lead
type: user_lookup
label: Assessment Lead
required: true
options:
filter:
employee_type: [internal] # internal | external | contractor
department: ["Quality Assurance"] # optional — OR logic between values
company_roles: [qa_manager, qa_supervisor] # optional — employee must hold at least one
hierarchy:
scope: all # all | same_department | subordinates | direct_reports
display: "{name} — {role}, {department}"
search:
min_length: 2
debounce_ms: 300
max_results: 20

Stored value — always an object snapshot:

{
"id": 42,
"name": "Alice Tan",
"email": "alice@company.com",
"role": "QA Manager",
"department": "Quality Assurance",
"employee_type": "internal"
}

Properties:

Property Required Description Default
options.filter.employee_type ❌ No List of employment types to include: internal, external, contractor All types
options.filter.department ❌ No Restrict results to employees in these departments (OR logic) All departments
options.filter.company_roles ❌ No Restrict results to employees holding at least one of these roles (OR logic) All roles
options.hierarchy.scope ❌ No Limit search to a reporting scope: all, same_department, subordinates, direct_reports all
display ❌ No Template for the text shown inside the field after selection (e.g. "{name} — {role}, {department}") "{name}"
search.min_length ❌ No Characters required before the search fires 2
search.debounce_ms ❌ No Milliseconds to wait between keystrokes before querying 300
search.max_results ❌ No Maximum number of results shown in the dropdown 20

Filter logic:

  • employee_type — applied as an IN clause; list all types you want included.
  • department — OR logic between values; employee must be in at least one.
  • company_roles — OR logic; employee must hold at least one of the listed roles.
  • All three filters are AND-combined when specified together.

Hierarchy scopes:

Scope Searches
all All employees matching the filter (default)
same_department Only employees in the requestor’s department
subordinates All direct and indirect reports of the requestor
direct_reports Only the requestor’s immediate direct reports

Security: On submission, the server re-fetches the selected employee using id + company_id and replaces the client-supplied snapshot with the canonical database record. Submitting an employee ID from a different company is rejected with HTTP 400. The search endpoint is also company-scoped via the session token.

When to use user_lookup vs autocomplete:

  • Use user_lookup for picking internal or external employees — it works without any Data Processor setup and enforces company isolation automatically.
  • Use autocomplete for non-employee entities (products, customers, locations) that come from an external data source via a Data Processor.

Common Uses: Assigning assessment leads, selecting requestors, choosing reviewers from a specific department, peer nomination, manager assignment


File attachment field. file_upload and file are aliases.

- name: receipt
type: file_upload
label: "Upload Receipt"
required: true
accept: ".pdf,.jpg,.png"
multiple: false
max_file_size: "5MB"

PDF-only upload:

- name: contract_document
type: file_upload
label: "Contract PDF"
required: true
accept: ".pdf,application/pdf"
max_file_size: "10MB"
help_text: "Upload the signed contract in PDF format"

Mobile camera capture:

- name: site_photo
type: file_upload
label: "Take a Photo"
accept: "image/*"
capture: "environment" # "environment" = rear camera, "user" = front camera

Properties:

Property Description
accept Comma-separated MIME types or extensions (e.g. ".pdf,.docx")
multiple Allow more than one file (true/false)
capture Force camera on mobile: "environment" or "user"
max_file_size Human-readable size limit (e.g. "5MB", "10MB")

Common Uses: Receipts, invoices, contracts, photos, supporting documents


Digital signature capture field. Pulls the user’s stored signature from their profile.

- name: requestor_signature
type: signature
label: "Your Signature"
required: true
help_text: "Sign to confirm your submission"

Test mode: Automatically uses /images/samplesignature.png — no real signatures needed during development or demos.

Production: Captures the logged-in user’s saved signature (text, drawn, or uploaded). Stored securely with the instance record.

Common Uses: Contract execution, policy acknowledgement, expense certification, approval sign-off


Display-only image field for logos, header images, and visual branding. Images can be sourced from the Media Gallery (System Settings → Media Gallery), a direct URL, or form data.

- name: company_logo
type: image
label: "Company Logo"
source: "company"
show_label: false
readonly: true
height: 64px
position: left

Upload any image in Admin → System Settings → Media Gallery and give it a name (e.g. approval_banner). Reference it in your YAML using that exact name as the source value:

- name: header_image
type: image
label: "Header Banner"
source: "approval_banner" # name of the asset in the Media Gallery
show_label: false
height: 120px
width: 100%
object_fit: cover
position: center

Use placement: background or placement: cover to render the image as a CSS background fill rather than an <img> tag. Useful for hero banners behind form content:

- name: banner
type: image
source: "hero_banner" # Media Gallery asset name
placement: cover # fills the container edge-to-edge
height: 160px
show_label: false

placement: background uses background-size: contain; placement: cover uses background-size: cover.

All properties:

Property Values Default Description
source asset name, "company", URL Image to display. A bare string matches a named Media Gallery asset; "company" uses the company logo from settings; a full URL (https://…) is used directly.
height CSS value 80px Max height (e.g. "64px", "200px").
width CSS value 100% Max width (e.g. "300px", "50%").
object_fit contain | cover | fill | scale-down contain How the image is resized within its box.
placement inline | background | cover inline inline renders an <img>; background/cover render a CSS background div.
position left | center | right left Horizontal alignment for inline placement.
show_label true | false true Set to false to hide the field label above the image.

Common Uses: Company branding in headers, workflow banners, product images, illustration separators



Dynamic repeating-row table. Users can add and remove rows; each row contains the configured item_fields. Supports calculated columns within rows.

- name: items
type: line_items
label: "Order Items"
required: true
min_items: 1
max_items: 20
item_fields:
- name: description
type: text
label: "Item Description"
required: true
- name: qty
type: number
label: "Qty"
required: true
min_value: 1
- name: unit_price
type: currency
label: "Unit Price"
required: true
currency: "USD"
- name: total
type: currency
label: "Total"
readonly: true
calculated: true
formula: "qty * unit_price"
currency: "USD"

Supported field types inside item_fields: text, number, currency, dropdown, select, textarea, autocomplete

Properties:

Property Description Default
min_items Minimum required rows 0
max_items Maximum allowed rows (hard cap: 100)
item_fields Column definitions (required)
header_groups Merged PDF column headers
blank_rows Extra empty PDF rows for handwritten notes 0
hide_when_empty Hide the field (label + table) entirely in PDF when it has no meaningful data false

Column-level properties:

Property Description
width Web read-only table column width
print_width PDF column width (falls back to width)
print_only If true, column is hidden from the web form and shown only in PDF

PDF grouped headers and handwritten-note columns:

- name: invoice_lines
type: line_items
label: Invoice Lines
item_fields:
- name: description
type: text
label: Description
width: 40%
print_width: 35%
- name: qty
type: number
label: Qty
align: right
print_width: 12%
- name: unit_price
type: currency
label: Unit Price
currency: IDR
align: right
print_width: 18%
- name: amount
type: currency
label: Amount
currency: IDR
align: right
print_width: 18%
- name: note_1
type: text
label: ""
print_only: true
print_width: 6%
- name: note_2
type: text
label: ""
print_only: true
print_width: 6%
header_groups:
- label: Article Details
span: 4
- label: Notes
span: 2
blank_rows: 3

The sum of all header_groups.*.span values must equal the number of item_fields.

Summary totals: Place a currency field outside line_items with formula: "sum(items.column_name)" to sum a column across all rows.

- name: grand_total
type: currency
label: "Grand Total"
readonly: true
calculated: true
formula: "sum(items.total)"
currency: "USD"

Common Uses: Purchase orders, invoices, expense reports, timesheets, material lists


Automatically generates a sequential, unique reference number at form submission. The number is assigned server-side — it is never editable by the user. Each workflow field maintains its own independent counter per company.

- name: po_number
type: autonumber
label: "PO Number"
prefix: "PO-"
pad_length: 5 # → PO-00001, PO-00042, PO-10000
start_value: 1

Properties:

Property Required Description Default
prefix ❌ No Text prepended to the number (e.g. "PO-", "EXP-", "INV-") ""
pad_length ❌ No Zero-pad the number to this many digits (e.g. 500042) No padding
start_value ❌ No First number in the sequence 1

How it works:

  1. The field renders as read-only with an “Auto-generated on submit” placeholder while the user fills out the form.
  2. On submission the server atomically increments the counter for (company_id, workflow_id, field_name) and formats the number as {prefix}{zero-padded number}.
  3. The generated value (e.g. PO-00001) is stored in the form data and visible to all approvers throughout the workflow.

Thread safety: Uses an atomic INSERT … ON CONFLICT DO UPDATE … RETURNING to guarantee uniqueness under concurrent submissions.

Database table: workflow_field_sequences (company_id, workflow_id, field_name, last_value)

Common Uses: Purchase order numbers, expense claim numbers, invoice numbers, ticket IDs, contract references

Examples:

# PO-00001, PO-00002, …
prefix: "PO-"
pad_length: 5
# EXP-2026-001, EXP-2026-002, … (manually include year in prefix)
prefix: "EXP-2026-"
pad_length: 3
# Plain numbers: 1, 2, 3, …
# (omit prefix and pad_length)

Fields that store metadata or pre-computed values — or that should appear only under certain form conditions. Included in form data but not shown when hidden.

Always hidden (engine-only):

- name: source_system
type: text
hidden: true
default: "HR-Portal"

Conditionally hidden via JSONata (truthy → hide). When hidden, the field is omitted from the web form, approval page, and PDF, and required is not enforced:

- name: other_reason
type: textarea
label: Please specify
required: true
hidden:
jsonata: "reason != 'other'"

Common Uses: Tracking codes, system IDs, computed values passed between steps, “Please specify” follow-ups that only appear for certain choices.

The same hidden shapes are supported on form.layout.sections[] — see Form Layouts.


Every field type accepts these properties:

Property Required Description
name ✅ Yes Unique snake_case identifier within the form
type ✅ Yes Field type (see table above)
label ✅ Yes Display label shown to the user
required ❌ No Whether the field must be filled (true/false, default false)
placeholder ❌ No Hint text shown inside empty input
help_text ❌ No Explanatory text shown below the field
default_value ❌ No Pre-filled value
readonly ❌ No Prevent user edits (combine with formula for calculated fields)

Set directly on the field (not nested under validation:):

- name: amount
type: number
min_value: 0
max_value: 100000
- name: notes
type: text
min_length: 10
max_length: 500
pattern: "^[A-Za-z0-9 ]+$" # Regex
- name: receipt
type: file_upload
max_file_size: "5MB"

Note: A validation: block in YAML is also accepted and is automatically unwrapped to the direct properties above.

Combine readonly: true, calculated: true, and formula to derive a value from other fields:

- name: total
type: currency
label: "Total"
readonly: true
calculated: true
formula: "qty * unit_price" # Inside line_items
currency: "USD"
- name: grand_total
type: currency
label: "Grand Total"
readonly: true
calculated: true
formula: "sum(items.total)" # Sum a line_items column
currency: "USD"

Supported operations: +, -, *, /, sum(), avg(), min(), max()

Show or hide a field based on other form values using hidden with a JSONata expression (truthy → hide):

- name: other_reason
type: textarea
label: "Please specify"
required: true
hidden:
jsonata: "reason != 'other'"

Prefer this over the older aspirational conditional.show_if shape — hidden: { jsonata } is what the runtime, validator, Studio, and PDF renderer understand.

style: "warning" # "warning" | "danger" | "success" | "info"

options:
- label: "Option 1"
value: "opt1"
- label: "Option 2"
value: "opt2"

Compatible with: dropdown, select, multiselect, radio

options:
data_processor:
source_id: "src_employees" # Registered Data Processor
value_field: "id" # Stored value
label_field: "name" # Display text
display: "{name} - {dept}" # Optional rich display template

Compatible with: autocomplete (required), dropdown, select, multiselect


I need to collect… Use
A name, title, or short text text
A long description or note textarea
An email address email
Formatted text with images richtext
A count or quantity number
A monetary amount currency
A calendar date (day only) date
A date with a specific time datetime
One choice from a list dropdown or select
Multiple choices from a list multiselect
A true/false toggle checkbox
One choice displayed as buttons radio with display_as: "buttons"
An internal employee (search by name, department, role) user_lookup
A searchable entity from an external source (product, customer…) autocomplete
An uploaded document or image file_upload or file
A captured signature signature
Repeating rows (purchase items, expenses…) line_items
An auto-generated sequential reference number autonumber
Hidden tracking metadata type: text + hidden: true

  • Use descriptive name values (e.g. employee_name, not field1)
  • Set required: true only for fields that are truly mandatory
  • Choose the most specific type (use email not text for email addresses)
  • Use dropdown for any field with ≤ 20 fixed options
  • Add placeholder and help_text to guide users
  • Put autonumber as the first field so it appears at the top of the form
  • Use min_items: 1 on line_items when at least one row is required
  • Use text when a specific type (email, date, currency) exists
  • Make every field required — it frustrates users
  • Define autocomplete with static options (use dropdown instead)
  • Forget validation bounds on number and currency fields
  • Use complex formula expressions without testing them

form:
fields:
# Auto-generated reference number
- name: expense_number
type: autonumber
label: "Expense Claim No."
prefix: "EXP-"
pad_length: 5
# Requestor details
- name: employee_name
type: text
label: "Employee Name"
required: true
- name: employee_email
type: email
label: "Email Address"
required: true
# Category selection
- name: category
type: dropdown
label: "Expense Category"
required: true
options:
- label: "Travel"
value: "travel"
- label: "Meals"
value: "meals"
- label: "Equipment"
value: "equipment"
- label: "Other"
value: "other"
# Conditional: only shown when category is "other"
- name: other_category
type: text
label: "Specify Category"
conditional:
show_if: "category == 'other'"
# Date and urgency
- name: expense_date
type: date
label: "Expense Date"
required: true
- name: urgency
type: radio
label: "Urgency"
required: true
display_as: "buttons"
options:
- label: "Normal"
value: "normal"
- label: "Urgent"
value: "urgent"
# Line items with calculated totals
- name: items
type: line_items
label: "Expense Items"
required: true
min_items: 1
max_items: 30
item_fields:
- name: description
type: text
label: "Description"
required: true
- name: amount
type: currency
label: "Amount"
required: true
currency: "USD"
- name: total_amount
type: currency
label: "Total Amount"
readonly: true
calculated: true
formula: "sum(items.amount)"
currency: "USD"
# Justification and receipt
- name: justification
type: textarea
label: "Business Justification"
required: true
rows: 3
- name: receipt
type: file_upload
label: "Receipt(s)"
required: true
accept: ".pdf,.jpg,.jpeg,.png"
multiple: true
max_file_size: "10MB"
# Signature and hidden metadata
- name: requestor_signature
type: signature
label: "Employee Signature"
required: true
- name: submitted_via
type: text
hidden: true
default: "web-form"

Structured data field for storing and displaying JSON objects or arrays. In edit mode, it provides a code editor with validation; in read-only mode, it supports an interactive, expandable tree view.

- name: api_payload
type: json
label: "Technical Details"
display_as: "tree" # → Interactive expandable tree view
required: true
default_value: '{"status": "pending", "meta": {}}'

Properties:

Property Required Description Default
display_as ❌ No How to render the data in read-only mode: "tree" (expandable), "code" (syntax highlighted), or "pretty" (formatted text). "pretty"

Common Uses: API request/response logs, system configurations, complex metadata, audit logs from external systems



Version: 1.2 Last Updated: 2026-06-30 Status: Production Ready ✅