Skip to content

Conditional Logic

Fields can be shown, hidden, or conditionally required based on the value or presence of other fields. Conditional logic works in every DocSpring form: simple web forms, visual forms, and data requests. It is also enforced when you submit data via the API.

  1. Select a field in the template editor.
  2. Scroll down to the Conditional Logic section.
  3. Click + Add Condition.
  4. Choose the Action, the source Field, an Operator, and a value (if the operator needs one).

You can add multiple conditions to a rule, and choose whether all or any of the conditions must match.

  • Show and require: The field is only shown (and required) when the conditions match. This is the most common action.
  • Show: The field is only shown when the conditions match. If the field’s own Required option is checked, it is “required when visible”.
  • Require: The field is always shown, but only required when the conditions match.
OperatorDescription
is presentThe field has any non-blank value
is blankThe field is empty
equalsThe field’s value matches exactly
does not equalThe field is blank, or has a different value
is one ofThe field’s value matches one of the listed values
>, , <, Numeric comparisons (for Number fields)
is betweenThe value is within an inclusive numeric range

Click an object or array group in the field list to apply one rule to every field in that group. This is useful for hiding a whole section — for example, hiding 24 “Dependent Information” fields when someone selects “decline coverage”:

  • Source Field: selected_coverage
  • Operator: does not equal
  • Value: decline
  • Action: Show and require

When “decline” is selected, every field in the group is hidden and none of them are required.

  • Hidden fields are never required. A required field that is hidden by a condition will not block form submission.
  • Hidden field values are not submitted. If someone fills in a field and then a condition hides it, the value is excluded from the submitted data (and from the generated PDF). The typed value reappears if the condition shows the field again.
  • Hidden fields are never rendered. Values for condition-hidden fields are also stripped on the server when a PDF is generated, so data submitted via the API renders exactly like a form submission. The stored submission data is not modified — only the rendered output.
  • Conditions can be chained. A condition’s source field can itself be conditionally shown. A hidden source field always counts as blank.
  • Sample data respects conditions. Generated example data (API code examples, the template editor’s random test data) leaves out fields that would be hidden.

Conditional logic is expressed in your template’s JSON schema using standard JSON Schema draft-07 if/then conditionals, in the same shape that generic JSON Schema form renderers such as react-jsonschema-form understand — so you can render the schema directly with your own form library (and the conditional fields will be shown, hidden, and required exactly like in DocSpring’s forms), validate data with any JSON Schema validator, or hand the schema to an AI agent that fills out your form.

  • Conditionally shown fields are only defined inside the conditional. A field that is shown by a condition (the Show and Show and require actions) is not defined in the base properties: the base schema only contains an empty placeholder ({}) at the field’s position, and the field’s full definition lives in the then branch of its conditional in the top-level allOf. When every field in an object group is shown by the same condition, the whole group is a single placeholder, and the group’s full definition lives in the conditional. The placeholder keeps the field’s position (so form renderers keep your field order when they merge the then branch into the schema), and keeps additionalProperties: false working; any stale value for a hidden field is accepted (and ignored by DocSpring).
  • Conditionally required fields are listed in the then branch’s required array. Rule targets are never in the base required array, so data that omits hidden fields validates correctly. A Show field that is itself marked required is “required when visible”; a Require field (always visible) stays in the base properties and its conditional only adds required.
  • Rules are combined per field, so a field hidden by one rule is never required by another, and a condition on a source field that is itself conditionally shown only matches while that source is visible (a hidden source counts as blank).
  • Annotation: each dependent field’s definition carries an x-field-dependencies array describing its rules in a machine-readable format (including a requiredWhenMatched flag). The conditionals DocSpring generates are marked x-docspring-field-dependencies: true.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"additionalProperties": false,
"properties": {
"coverage": {
"type": "string",
"enum": ["employee", "family", "decline"]
},
"beneficiary": {}
},
"required": ["coverage"],
"allOf": [
{
"if": {
"required": ["coverage"],
"properties": {
"coverage": { "not": { "enum": [null, ""] }, "const": "family" }
}
},
"then": {
"properties": {
"beneficiary": {
"type": "string",
"title": "Beneficiary",
"x-field-dependencies": [
{
"action": "require_and_show",
"match": "all",
"conditions": [
{
"field": "coverage",
"operator": "equals",
"value": "family"
}
],
"requiredWhenMatched": true
}
]
}
},
"required": ["beneficiary"]
},
"x-docspring-field-dependencies": true
}
]
}

Per-field rules are stored in the dependencies property of each shared field, and group rules are stored in the template’s field_dependencies array. You can set both with the Update Template endpoint:

{
"template": {
"shared_field_data": {
"beneficiary": {
"name": "beneficiary",
"type": "string",
"required": false,
"dependencies": {
"action": "require_and_show",
"match": "all",
"conditions": [
{ "field": "coverage", "operator": "equals", "value": "family" }
]
}
}
},
"field_dependencies": [
{
"action": "require_and_show",
"match": "all",
"conditions": [
{ "field": "coverage", "operator": "not_equals", "value": "decline" }
],
"targets": ["dependent_name", "dependent_dob"]
}
]
}
}
  • action: require_and_show, show, or require
  • match: all or any
  • operator: present, blank, equals, not_equals, in, gt, gte, lt, lte, or range (use value for the lower bound and rangeMax for the upper bound). The numeric operators (gt, gte, lt, lte, range) are only valid when the source field is a Number field, and require numeric values (range needs at least one bound; a missing bound makes the range open-ended).
  • Field names use the same a/b/c path syntax as nested field names