Form Field Types Reference
Form Field Types Reference
Section titled “Form Field Types Reference”Complete reference for all supported form field types in ApprovalML workflows.
Quick Reference
Section titled “Quick Reference”| 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 |
Text Input Fields
Section titled “Text Input Fields”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: 100Common Uses: Names, titles, short descriptions, IDs, reference codes
textarea
Section titled “textarea”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: 1000Common 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
richtext
Section titled “richtext”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
Section titled “markdown”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: 5000Features:
- 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 Fields
Section titled “Numeric Fields”number
Section titled “number”Numeric input accepting integers or decimals.
- name: quantity type: number label: "Quantity" required: true placeholder: "0" min_value: 1 max_value: 1000Properties:
| Property | Description |
|---|---|
min_value | Minimum allowed value |
max_value | Maximum allowed value |
Common Uses: Quantities, counts, percentages, ratings, days
currency
Section titled “currency”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: 1000000Properties:
| 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
Date & Time Fields
Section titled “Date & Time Fields”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
datetime
Section titled “datetime”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: trueProperties:
| 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
datewhen only the calendar day matters (payment date, deadline, travel date) - Use
datetimewhen the time of day is relevant (meeting time, submission cut-off, event schedule)
Selection Fields
Section titled “Selection Fields”dropdown / select
Section titled “dropdown / select”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
multiselect
Section titled “multiselect”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
checkbox
Section titled “checkbox”Single boolean toggle for true/false responses.
- name: agree_to_terms type: checkbox label: "I agree to the terms and conditions" required: trueCommon Uses: Agreements, acknowledgements, opt-ins, feature flags
autocomplete
Section titled “autocomplete”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
user_lookup
Section titled “user_lookup”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: 20Stored 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_lookupfor picking internal or external employees — it works without any Data Processor setup and enforces company isolation automatically. - Use
autocompletefor 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 & Media Fields
Section titled “File & Media Fields”file_upload / file
Section titled “file_upload / file”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 cameraProperties:
| 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
signature
Section titled “signature”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.
Basic example — company logo
Section titled “Basic example — company logo”- name: company_logo type: image label: "Company Logo" source: "company" show_label: false readonly: true height: 64px position: leftUsing a named Media Gallery asset
Section titled “Using a named Media Gallery asset”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: centerBackground / cover placement
Section titled “Background / cover placement”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: falseplacement: 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
Advanced Fields
Section titled “Advanced Fields”line_items
Section titled “line_items”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) | — |
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
autonumber
Section titled “autonumber”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: 1Properties:
| 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. 5 → 00042) | No padding |
start_value | ❌ No | First number in the sequence | 1 |
How it works:
- The field renders as read-only with an “Auto-generated on submit” placeholder while the user fills out the form.
- On submission the server atomically increments the counter for
(company_id, workflow_id, field_name)and formats the number as{prefix}{zero-padded number}. - 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)hidden fields
Section titled “hidden fields”Fields that store metadata or pre-computed values. Included in form data but never shown to the user. Use type: text (or other appropriate type) and set hidden: true.
- name: source_system type: text hidden: true default: "HR-Portal"Common Uses: Tracking codes, system IDs, computed values passed between steps, version markers
Field Properties Reference
Section titled “Field Properties Reference”Universal Properties
Section titled “Universal Properties”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) |
Validation Properties
Section titled “Validation Properties”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.
Formula / Calculated Fields
Section titled “Formula / Calculated Fields”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()
Conditional Display
Section titled “Conditional Display”Show or hide a field based on another field’s value:
- name: other_reason type: textarea label: "Please specify" conditional: show_if: "reason == 'other'"Visual Styling
Section titled “Visual Styling”style: "warning" # "warning" | "danger" | "success" | "info"Dynamic Options (Data Processors)
Section titled “Dynamic Options (Data Processors)”Static Options
Section titled “Static Options”options: - label: "Option 1" value: "opt1" - label: "Option 2" value: "opt2"Compatible with: dropdown, select, multiselect, radio
Dynamic Data Processor
Section titled “Dynamic Data Processor”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 templateCompatible with: autocomplete (required), dropdown, select, multiselect
Field Type Selection Guide
Section titled “Field Type Selection Guide”| 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 |
Best Practices
Section titled “Best Practices”- Use descriptive
namevalues (e.g.employee_name, notfield1) - Set
required: trueonly for fields that are truly mandatory - Choose the most specific type (use
emailnottextfor email addresses) - Use
dropdownfor any field with ≤ 20 fixed options - Add
placeholderandhelp_textto guide users - Put
autonumberas the first field so it appears at the top of the form - Use
min_items: 1online_itemswhen at least one row is required
❌ Don’t:
Section titled “❌ Don’t:”- Use
textwhen a specific type (email,date,currency) exists - Make every field
required— it frustrates users - Define
autocompletewith static options (usedropdowninstead) - Forget validation bounds on
numberandcurrencyfields - Use complex
formulaexpressions without testing them
Complete Example
Section titled “Complete Example”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
Related Documentation
Section titled “Related Documentation”Version: 1.2 Last Updated: 2026-06-30 Status: Production Ready ✅