Nested Forms in SurveyJS — Link Parent Answers to Nested Subforms (Part 3)

Parts 1 and 2 covered nested contacts and catalog lines—records that contain text and choice fields. Part 3 adds what those forms did not: a child subform that appears conditionally when a parent answer requires it, with each nested entry including a file upload.

Nested forms in SurveyJS: conditional nested subform linked to a parent answer

In This Series

This three-part guide uses a supplier registration example to show how to build nested forms in SurveyJS:

Example

Try the following live demo. Answer "Yes" to the "Do you supply hazardous materials?" question to reveal the Safety Data Sheet (SDS) subform in tab mode. Add substances and upload PDFs.

Open Demo in StackBlitz

Business Scenario: Hazardous Materials SDS

When a supplier answers "Yes" to "Do you supply hazardous materials?", they must add one SDS entry per substance: name, UN number, and a PDF upload. If they answer "No", the page remains hidden—no empty nested panel and no forced uploads.

Survey JSON

The Dynamic Panel is configured with "displayMode": "tab" and a hidden Expression for tab titles (the same pattern as Part 2). The page visibility is controlled with the visibleIf expression.

{
  "title": "Supplier Registration — Hazardous materials",
  "pages": [
    {
      "name": "profile",
      "title": "Supplier profile",
      "elements": [
        {
          "type": "text",
          "name": "legalName",
          "title": "Legal company name",
          "isRequired": true
        },
        {
          "type": "boolean",
          "name": "shipsHazmat",
          "title": "Do you supply hazardous materials?",
          "isRequired": true
        }
      ]
    },
    {
      "name": "hazmat",
      "visibleIf": "{shipsHazmat} = true",
      "title": "Safety data sheets",
      "description": "Upload one SDS PDF for each hazardous substance supplied by {legalName}",
      "elements": [
        {
          "type": "paneldynamic",
          "name": "safetyDataSheets",
          "title": "Safety data sheets (SDS)",
          "templateElements": [
            {
              "type": "expression",
              "name": "tabTitle",
              "visible": false,
              "expression": "iif({panel.substanceName} empty, 'New SDS entry', {panel.substanceName} + ' — UN ' + {panel.unNumber})"
            },
            {
              "type": "text",
              "name": "substanceName",
              "title": "Substance name",
              "isRequired": true
            },
            {
              "type": "text",
              "name": "unNumber",
              "title": "UN number",
              "isRequired": true,
              "maskType": "pattern",
              "maskSettings": {
                "pattern": "9999"
              }
            },
            {
              "type": "file",
              "name": "sdsFile",
              "title": "Upload SDS (PDF)",
              "isRequired": true,
              "acceptedTypes": "application/pdf",
              "maxSize": 5242880
            }
          ],
          "templateTitle": "{panel.tabTitle}",
          "templateTabTitle": "{panel.tabTitle}",
          "panelCount": 1,
          "minPanelCount": 1,
          "maxPanelCount": 20,
          "addPanelText": "Add SDS entry",
          "removePanelText": "Remove SDS entry",
          "displayMode": "tab"
        }
      ]
    }
  ]
}

In production, upload files to your server rather than storing them as base64 in the survey results JSON. SurveyJS supports server-side upload via the onUploadFiles event. See the File Upload demo for a complete example.

Patterns for Connecting Parent and Nested Data

Conditional Pages (visibleIf)

Hide the nested subform until a parent answer makes it relevant. Hidden sections are typically skipped during validation and are not included in results, keeping payloads clean.

Conditional Required Nested Entries

Combine visibleIf on the page with minPanelCount: 1 on the Dynamic Panel so at least one SDS (with PDF) is required only when the answer is Yes.

Dynamic Titles from Parent Context

Reference parent fields in nested page content (see hazmatIntro): {legalName} updates when the respondent changes the profile answer.

Syncing Two Nested Sections

When one list drives another (for example, pick departments, then add a contact per department), use a shared valueName join identifier. See How to sync data within a form using a join identifier.

Sample Result JSON

No hazardous materials — profile only:

{
  "legalName": "Acme Fasteners Inc.",
  "shipsHazmat": false
}

Hazardous material supplier — profile plus nested SDS array (one object per substance). In a demo, file content may appear as base64 in JSON; in production, store file URLs returned from your server:

{
  "legalName": "ChemSupply Ltd.",
  "shipsHazmat": true,
  "safetyDataSheets": [
    {
      "substanceName": "Industrial solvent",
      "unNumber": "1263",
      "sdsFile": [
        {
          "name": "solvent-sds.pdf",
          "type": "application/pdf",
          "content": "data:application/pdf;base64,..."
        }
      ],
      "tabTitle": "Industrial solvent — UN 1263"
    }
  ]
}

Your API can store supplier profile fields and route safetyDataSheets to a documents table. Contacts and product lines from Parts 1 and 2 can be linked under the same supplier ID in your backend.

SurveyJS is built primarily for data collection. Nested forms help you capture related records in one submission. Searching, filtering, and managing existing supplier data are usually handled by your application—not in the form session itself.

Your cookie settings

We use cookies to make your browsing experience more convenient and personal. Some cookies are essential, while others help us analyse traffic. Your personal data and cookies may be used for ad personalization. By clicking “Accept All”, you consent to the use of all cookies as described in our Terms of Use and Privacy Statement. You can manage your preferences in “Cookie settings.”

Your renewal subscription expires soon.

Since the license is perpetual, you will still have permanent access to the product versions released within the first 12 month of the original purchase date.

If you wish to continue receiving technical support from our Help Desk specialists and maintain access to the latest product updates, make sure to renew your subscription by clicking the "Renew" button below.

Your renewal subscription has expired.

Since the license is perpetual, you will still have permanent access to the product versions released within the first 12 month of the original purchase date.

If you wish to continue receiving technical support from our Help Desk specialists and maintain access to the latest product updates, make sure to renew your subscription by clicking the "Renew" button below.