OpenForm

field

Last updated on

Define form fields for data capture

Define form fields for capturing user input. OpenForm supports 21 field types covering text, numeric, temporal, entity, spatial, and selection inputs.

Examples

Creating fields

// Text field with validation
const nameField = field.text()
  .label('Full Name')
  .description('Enter your legal name')
  .required()
  .minLength(2)
  .maxLength(100)
  .build()

// Enum/select field
const statusField = field.enum()
  .label('Status')
  .options(['active', 'inactive', 'pending'])
  .default('pending')
  .build()

// Nested fieldset
const addressField = field.fieldset()
  .label('Address')
  .fields({
    street: { type: 'text', label: 'Street' },
    city: { type: 'text', label: 'City' },
    zip: { type: 'text', label: 'ZIP Code' }
  })
  .build()

Adding fields to forms

// Object pattern
const form = open.form({
  name: 'contact-form',
  fields: {
    name: { type: 'text', label: 'Name', required: true },
    email: { type: 'email', label: 'Email', required: true },
    age: { type: 'number', label: 'Age', min: 0, max: 150 }
  }
})

// Builder pattern
const form = open.form()
  .name('contact-form')
  .field('name', field.text().label('Name').required().build())
  .field('email', field.email().label('Email').required().build())
  .field('age', field.number().label('Age').min(0).max(150).build())
  .build()

Field Types

Text-based

TypeDescriptionBuilder
textFree-form text inputfield.text()
emailEmail addressfield.email()
uuidUUID stringfield.uuid()
uriURL/URIfield.uri()

Numeric

TypeDescriptionBuilder
numberNumeric inputfield.number()
percentagePercentage (0-100)field.percentage()
ratingRating scale (1-5 default)field.rating()
moneyMonetary amountfield.money()

Boolean

TypeDescriptionBuilder
booleanCheckbox/togglefield.boolean()

Selection

TypeDescriptionBuilder
enumSingle-select dropdownfield.enum()
multiselectMulti-selectfield.multiselect()

Temporal

TypeDescriptionBuilder
dateDate (YYYY-MM-DD)field.date()
datetimeDate and timefield.datetime()
timeTime onlyfield.time()
durationISO 8601 durationfield.duration()

Entity

TypeDescriptionBuilder
personPerson informationfield.person()
organizationOrganization infofield.organization()
identificationID documentfield.identification()

Spatial

TypeDescriptionBuilder
coordinateLat/lng pointfield.coordinate()
bboxBounding boxfield.bbox()
addressPostal addressfield.address()
phonePhone numberfield.phone()

Container

TypeDescriptionBuilder
fieldsetNested fieldsfield.fieldset()

API

Field Builder

The field function creates field builders:

field()                     // Returns TextFieldBuilder (default)
field(input: FormField)     // Validates and returns FormField
field.text()                // Returns TextFieldBuilder
field.number()              // Returns NumberFieldBuilder
// ... etc for each field type

Common Builder Methods

All field builders share these methods:

All methods return FieldBuilder and are chainable.

field.*()
label: (value: string) => FieldBuilder
Set human-readable label
description: (value: string) => FieldBuilder
Set helper text
required: (value?: boolean | string) => FieldBuilder
Mark as required (default: true). Accepts expression.
visible: (value?: boolean | string) => FieldBuilder
Set visibility (default: true). Accepts expression.
build: () => FormField
Build and validate

Type-Specific Methods

Text / Email / UUID / URI

minLength: (value: number) => this
Minimum character length
maxLength: (value: number) => this
Maximum character length
pattern: (value: string) => this
Regex pattern for validation
default: (value: string) => this
Default value

Number

min: (value: number) => this
Minimum allowed value
max: (value: number) => this
Maximum allowed value
default: (value: number) => this
Default value

Money

min: (value: number) => this
Minimum amount
max: (value: number) => this
Maximum amount
default: (value: Money) => this
Default value ({ amount, currency })

Boolean

default: (value: boolean) => this
Default value

Enum

options: (values: (string | number)[]) => this
Available options
default: (value: string | number) => this
Default selection

Multiselect

options: (values: (string | number)[]) => this
Available options
min: (value: number) => this
Minimum selections required
max: (value: number) => this
Maximum selections allowed
default: (value: (string | number)[]) => this
Default selections

Date / Datetime / Time

min: (value: string) => this
Minimum date/time (ISO format)
max: (value: string) => this
Maximum date/time (ISO format)
default: (value: string) => this
Default value (ISO format)

Percentage

min: (value: number) => this
Minimum percentage
max: (value: number) => this
Maximum percentage
precision: (value: number) => this
Decimal places
default: (value: number) => this
Default value

Rating

min: (value: number) => this
Minimum rating
max: (value: number) => this
Maximum rating
step: (value: number) => this
Rating increment
default: (value: number) => this
Default value

Identification

allowedTypes: (...types: string[]) => this
Allowed ID document types
default: (value: Identification) => this
Default value

Fieldset

fields: (fields: Record<string, FormField>) => this
Nested field definitions

Static Methods

parse: (input: unknown) => FormField
Parse unknown input (throws on error)
safeParse: (input: unknown) => Result<FormField>
Parse unknown input (returns result object)

Common Properties

All fields share these base properties:

type: string
Field type discriminator
label?: string
Human-readable label
description?: string
Helper text displayed in UI
required?: boolean | string
Whether field is required. Can be an expression.
visible?: boolean | string
Whether field is visible. Can be an expression.
disabled?: boolean | string
Whether field is read-only. Can be an expression.
attrs?: Record<string, string | number | boolean>
Custom metadata attributes

Conditional Logic

The required, visible, and disabled properties can be expressions that reference logic keys:

const form = open.form()
  .name('age-form')
  .expr('isAdult', 'age >= 18')
  .field('age', field.number().label('Age').required().build())
  .field('drivingLicense', field.text()
    .label('Driving License')
    .visible('isAdult')
    .required('isAdult')
    .build())
  .build()

Related

On this page