Create Form artifacts with fields, parties, and signing flows
Create Form artifacts for interactive forms with fields, signing parties, and document annexes.
Examples
Creating a form
// Object pattern
const form = open. form ({
name: 'lease-agreement' ,
version: '1.0.0' ,
title: 'Residential Lease Agreement' ,
fields: {
tenantName: { type: 'text' , label: 'Tenant Name' , required: true },
moveInDate: { type: 'date' , label: 'Move-in Date' },
monthlyRent: { type: 'money' , label: 'Monthly Rent' , min: 0 }
},
parties: {
tenant: { label: 'Tenant' , partyType: 'person' , signature: { required: true } },
landlord: { label: 'Landlord' , signature: { required: true , witnesses: 1 } }
},
annexes: {
photoId: { title: 'Photo ID' , required: true }
},
layers: {
html: { kind: 'inline' , mimeType: 'text/html' , text: '<p>Tenant: {{tenantName}}</p>' }
},
defaultLayer: 'html'
})
// Builder pattern
const form = open. form ()
. name ( 'lease-agreement' )
. version ( '1.0.0' )
. title ( 'Residential Lease Agreement' )
. field ( 'tenantName' , field. text (). label ( 'Tenant Name' ). required (). build ())
. field ( 'moveInDate' , field. date (). label ( 'Move-in Date' ). build ())
. field ( 'monthlyRent' , field. money (). label ( 'Monthly Rent' ). min ( 0 ). build ())
. party ( 'tenant' , party (). label ( 'Tenant' ). partyType ( 'person' )
. signature ({ required: true }). build ())
. party ( 'landlord' , party (). label ( 'Landlord' )
. signature ({ required: true , witnesses: 1 }). build ())
. annex ( 'photoId' , annex (). title ( 'Photo ID' ). required (). build ())
. inlineLayer ( 'html' , { mimeType: 'text/html' , text: '<p>Tenant: {{tenantName}}</p>' })
. defaultLayer ( 'html' )
. build ()
Loading from external data
// Parse and validate unknown input (throws on error)
const form = open.form. from (jsonData)
// Safe parsing (returns result object)
const result = open.form. safeFrom (jsonData)
if (result.success) {
const form = result.data
}
Form Lifecycle
Forms follow a three-phase lifecycle: Draft → Signable → Executed.
// 1. Fill form to create DraftForm (mutable data)
const draft = form. fill ({
fields: { tenantName: 'John Doe' , moveInDate: '2024-02-01' },
parties: {
tenant: { id: 'tenant-0' , fullName: 'John Doe' },
landlord: { id: 'landlord-0' , legalName: 'ABC Property LLC' }
}
})
// 2. Configure signers and signatories
const ready = draft
. addSigner ( 'john' , {
person: { fullName: 'John Doe' },
adopted: { signature: { image: 'data:...' , method: 'drawn' } }
})
. addSignatory ( 'tenant' , 'tenant-0' , { signerId: 'john' })
// 3. Prepare for signing (SignableForm - data frozen)
const signable = ready. prepareForSigning ()
// 4. Capture signatures
const signed = signable. captureSignature ( 'tenant' , 'tenant-0' , 'john' , 'final-sig' )
// 5. Finalize (ExecutedForm - fully frozen)
const executed = signed. finalize ()
// 6. Render the executed form
const output = await executed. render ({ renderer: textRenderer })
API
Object Pattern
open. form (input: FormInput): FormInstance
Parameters
name : string
Unique identifier; must follow slug constraints
version ?: string
Artifact version (semantic versioning)
title ?: string
Human-friendly name presented to end users
description ?: string
Long-form description or context
code ?: string
Internal code or reference number
releaseDate ?: string
ISO date when artifact was released
metadata ?: Metadata
Custom metadata map
logic ?: LogicSection
Named expressions for conditional logic
fields ?: Record<string, FormField>
Field definitions keyed by identifier
layers ?: Record<string, Layer>
Named layers for rendering
defaultLayer ?: string
Key of default layer for rendering
annexes ?: Record<string, FormAnnex>
Predefined annex slots keyed by identifier
allowAdditionalAnnexes ?: boolean
Allow ad-hoc annexes beyond defined slots
parties ?: Record<string, FormParty>
Party role definitions
Returns
Returns a FormInstance with the following properties and methods:
kind : 'form'
Artifact discriminator
version : string | undefined
Semantic version
title : string | undefined
Human-readable title
description : string | undefined
Description text
code : string | undefined
Internal code
releaseDate : string | undefined
ISO date string
metadata : Metadata | undefined
Custom metadata map
logic : LogicSection | undefined
Named logic expressions
fields : Record<string, FormField> | undefined
Field definitions
layers : Record<string, Layer> | undefined
Render layers
defaultLayer : string | undefined
Default layer key
annexes : Record<string, FormAnnex> | undefined
Annex slot definitions
allowAdditionalAnnexes : boolean | undefined
Allow ad-hoc annexes
parties : Record<string, FormParty> | undefined
Party role definitions
parseData : (data: Record<string, unknown>) => InferFormPayload
Validate data against form (throws on error)
safeParseData : (data: Record<string, unknown>) => ValidationResult
Validate data (returns result object)
fill : (data: FillOptions) => DraftForm
Create a DraftForm with validated data
safeFill : (data: FillOptions) => Result<DraftForm>
Create DraftForm (returns result object)
render : (options: RenderOptions) => Promise<Output>
Render using a renderer
clone : () => FormInstance
Deep clone the instance
validate : (options?: ValidateOptions) => StandardSchemaV1.Result
Validate the form definition
isValid : (options?: ValidateOptions) => boolean
Check if form is valid
toJSON : (options?: SerializationOptions) => object
Serialize to JSON
toYAML : (options?: SerializationOptions) => string
Serialize to YAML
Builder Pattern
Chain methods to build a form incrementally:
All methods return FormBuilder and are chainable.
open.form()
name : (value: string) => FormBuilder Set form name (required)
version : (value: string) => FormBuilder Set semantic version
title : (value: string) => FormBuilder Set human-readable title
description : (value: string) => FormBuilder Set description
code : (value: string) => FormBuilder Set external reference code
releaseDate : (value: string) => FormBuilder Set release date (ISO format)
metadata : (value: Metadata) => FormBuilder Set custom metadata
logic : (value: LogicSection) => FormBuilder Set logic expressions
expr : (name: string, expression: string) => FormBuilder Add a single logic expression
field : (id: string, field: FormField) => FormBuilder Add a single field
fields : (fields: Record<string, FormField>) => FormBuilder Set all fields at once
layers : (value: Record<string, Layer>) => FormBuilder Set all layers at once
layer : (key: string, layer: Layer) => FormBuilder Add a layer
inlineLayer : (key: string, layer: { mimeType, text, ... }) => FormBuilder Add inline text layer
fileLayer : (key: string, layer: { mimeType, path, ... }) => FormBuilder Add file-backed layer
defaultLayer : (key: string) => FormBuilder Set default layer for rendering
annex : (annexId: string, annex: FormAnnex) => FormBuilder Add a single annex slot
annexes : (annexes: Record<string, FormAnnex>) => FormBuilder Set all annexes at once
allowAdditionalAnnexes : (value: boolean) => FormBuilder Allow ad-hoc annexes
party : (roleId: string, party: FormParty) => FormBuilder Add a party role
parties : (parties: Record<string, FormParty>) => FormBuilder Set all parties at once
build : () => FormInstance Build and validate
Static Methods
Parse forms from unknown data sources:
from : (input: unknown) => FormInstance
Parse unknown input (throws on error)
safeFrom : (input: unknown) => Result<FormInstance>
Parse unknown input (returns result object)
Data Validation
FormInstance provides Zod-style methods for validating data:
// Throws FormValidationError if validation fails
const validated = form. parseData ({ fields: { tenantName: 'John' } })
// Returns result object
const result = form. safeParseData ({ fields: { tenantName: 'John' } })
if (result.success) {
console. log (result.data)
} else {
console. error (result.errors)
}
Lifecycle Types
The fill() method returns a DraftForm that follows the form lifecycle:
Type Phase Data Signatures DraftFormDraft Mutable Configure signers/signatories SignableFormSignable Frozen Capture signatures ExecutedFormExecuted Frozen Frozen (complete)
DraftForm
Created by form.fill(). Mutable data and signer configuration.
phase : 'draft'
Phase discriminator
form : Form
The embedded form definition
data : InferFormPayload
The validated data payload
parties : Record<string, Party | Party[]>
Party data by role ID
signers : Record<string, Signer>
Global signer registry
signatories : Record<string, Record<string, PartySignatory[]>>
Signatories by role/party
targetLayer : string
Current rendering layer
runtimeState : FormRuntimeState
Evaluated logic state
getField : (fieldId: string) => T | undefined
Get a field value
getAllFields : () => Record<string, unknown>
Get all field values
setField : (fieldId: string, value: T) => DraftForm
Update a field (immutable)
updateFields : (partial: Record<string, unknown>) => DraftForm
Update multiple fields
getParty : (roleId: string) => Party | Party[] | undefined
Get party for role
setParty : (roleId: string, party: Party | Party[]) => DraftForm
Set party (immutable)
addParty : (roleId: string, party: Party) => DraftForm
Add party to role
addSigner : (signerId: string, signer: Signer) => DraftForm
Add signer to registry
addSignatory : (roleId, partyId, signatory) => DraftForm
Link signer to party
prepareForSigning : () => SignableForm
Transition to signable phase
seal : (adapter: Sealer) => Promise<SignableForm>
Seal for formal e-signing
render : (options: RenderOptions) => Promise<Output>
Render with embedded data
toJSON : () => DraftFormJSON
Serialize to JSON
toYAML : () => string
Serialize to YAML
SignableForm
Created by draft.prepareForSigning() or draft.seal(). Frozen data, signature capture allowed.
phase : 'signable'
Phase discriminator
isFormal : boolean
True if created via seal()
signatureMap : SigningField[] | undefined
Signature field coordinates (formal only)
canonicalPdfHash : string | undefined
PDF hash (formal only)
captures : SignatureCapture[]
Captured signatures
witnesses : WitnessParty[]
Declared witnesses
attestations : Attestation[]
Witness attestations
captureSignature : (role, partyId, signerId, locationId, options?) => SignableForm
Capture signature at location
captureInitials : (role, partyId, signerId, locationId, options?) => SignableForm
Capture initials at location
addWitness : (witness: WitnessParty) => SignableForm
Add a witness
addAttestation : (attestation: Attestation) => SignableForm
Add attestation
getSignatureStatus : (roleId: string) => SignatureStatus
Get status for role
getOverallSignatureStatus : () => OverallSignatureStatus
Get overall progress
finalize : () => ExecutedForm
Transition to executed phase
ExecutedForm
Created by signable.finalize(). Fully frozen, ready for archival.
phase : 'executed'
Phase discriminator
executedAt : string
ISO timestamp of execution
getCaptures : () => SignatureCapture[]
Get all captures
getWitnesses : () => WitnessParty[]
Get all witnesses
getAttestations : () => Attestation[]
Get all attestations
render : (options: RenderOptions) => Promise<Output>
Render the executed form
toJSON : () => ExecutedFormJSON
Serialize to JSON
Related