OpenForm
SDKArtifactsform

fill-state

Last updated on

Track form completion progress with FillState

Query the fill state of a DraftForm to determine what's been filled, what's still needed, and what to ask next. FillState evaluates conditional visibility, required expressions, and dependency chains to give an accurate picture of form progress.

Examples

Basic usage

const draft = form.partialFill({
  fields: { tenantName: 'John Doe' }
})

const state = draft.getFillState()

state.summary.completionPercent  // e.g. 25
state.summary.requiredRemaining  // e.g. 3
state.next                       // { kind: 'party', key: 'tenant', required: true, order: 0 }

Progressive fill loop

let draft = form.partialFill()

while (true) {
  const state = draft.getFillState()
  if (state.summary.requiredRemaining === 0) break

  const target = state.next
  if (!target) break

  const value = await collectValueFromUser(target)

  draft = draft.update({
    [target.kind === 'party' ? 'parties' : 'fields']: {
      [target.key]: value
    }
  })
}

// All required data collected — fill the form
const filled = form.fill(draft.data)

Including optional targets

By default, candidates only includes required targets. Pass includeOptional: true to include optional fields:

const state = draft.getFillState({ includeOptional: true })
// state.candidates now includes both required and optional targets
// Required targets are listed first (requiredFirst defaults to true)

Checking blocked items

Items with conditional visibility that depends on unfilled fields appear in blocked:

const state = draft.getFillState()

for (const item of state.blocked) {
  console.log(`${item.key} is hidden, waiting on: ${item.blockedBy.join(', ')}`)
}
// e.g. "spouseName is hidden, waiting on: maritalStatus"

Checking rules

const state = draft.getFillState()

if (!state.rules.valid) {
  for (const error of state.rules.errors) {
    console.log(`Rule violation: ${error}`)
  }
}

API

FillState

Returned by draft.getFillState().

phase: 'draft' | 'signable' | 'executed'
Current form phase
summary: FillStateSummary
Progress summary with counts and completion percentage
defsValues: Record<string, unknown>
Current evaluated defs values
rules: { valid: boolean; errors: string[]; warnings: string[] }
Rules evaluation result
openRequired: FillItemState[]
Visible, unfilled, required items
openOptional: FillItemState[]
Visible, unfilled, optional items
blocked: FillItemState[]
Not visible — waiting on dependencies to be filled
done: FillItemState[]
Already filled items
candidates: FillTarget[]
Available fill targets in declaration order (parties first, then fields, then annexes)
next: FillTarget | null
First candidate — convenience shorthand for candidates[0]

FillStateSummary

requiredTotal: number
Total number of required items (visible and blocked)
requiredDone: number
Number of required items already filled
requiredRemaining: number
Number of required items still needed
completionPercent: number
Completion percentage (0–100)

FillTarget

A candidate target that can be filled next.

kind: FillTargetKind
'field', 'party', or 'annex'
key: string
Field id, role id, or annex id
required: boolean
Whether this target is required
order: number
Declaration order in schema

FillItemState

Extended fill target with runtime state. Used in openRequired, openOptional, blocked, and done arrays.

kind: FillTargetKind
'field', 'party', or 'annex'
key: string
Field id, role id, or annex id
required: boolean
Whether this target is required
order: number
Declaration order in schema
visible: boolean
Whether this item is currently visible
filled: boolean
Whether this item has been filled
blockedBy: string[]
IDs of unfilled fields/parties this depends on for visibility

FillTargetKind

type FillTargetKind = 'field' | 'party' | 'annex'

FillTargetOptions

Options for getFillState, getNextFillTarget, and getAvailableFillTargets.

requiredFirst?: boolean
Sort required targets before optional in candidates. Default: true
includeOptional?: boolean
Include optional targets in candidates. Default: false

PartialFillOptions

Options for partialFill and safePartialFill on FormInstance.

validate?: FillValidationMode
Validation mode: 'patch' (default), 'full', or 'none'
rules?: boolean
Evaluate and report rules. Default: false

UpdateOptions

Options for update and safeUpdate on DraftForm.

validate?: FillValidationMode
Validation mode: 'patch' (default), 'full', or 'none'
rules?: boolean
Evaluate and report rules. Default: false

SafePartialFillResult

Returned by safePartialFill and safeUpdate.

type SafePartialFillResult<F extends Form> =
  | { success: true; data: DraftForm<F> }
  | { success: false; error: Error }

FillValidationMode

type FillValidationMode = 'patch' | 'full' | 'none'
ModeBehavior
"patch"Validate only the provided fields (default)
"full"Validate entire payload including required fields
"none"Skip validation entirely

How visibility and blocking work

FillState evaluates conditional visible and required expressions on fields, parties, and annexes using the current data. Items are categorized as:

  • openRequired — visible, required, not yet filled. These are what the user needs to answer.
  • openOptional — visible, optional, not yet filled. Available but not blocking completion.
  • blocked — not visible because a dependency hasn't been filled yet. The blockedBy array shows which field or party needs a value first. Blocked items unblock automatically when their dependencies are filled.
  • done — already filled, regardless of visibility.

The candidates array contains all open (visible, unfilled) targets in declaration order. When requiredFirst is true (the default), required targets appear before optional ones.

Related

  • form - Form builder and lifecycle
  • field - Field definitions
  • party - Party role definitions
  • annex - Annex slot definitions

On this page