Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Create a Dynamic Questionnaire System in FlutterFlow

Build a questionnaire system that reads question definitions from Firestore, including input type, validation rules, and options. Render each question dynamically using Generate Dynamic Children with a Conditional Builder switching between TextField, DateTimePicker, RadioButton, and CheckboxGroup based on the inputType field. Collect all answers in a Page State Map, validate required fields and regex patterns on submit, and save responses to a questionnaire_responses collection.

What you'll learn

  • How to define questionnaire schemas in Firestore with typed question documents
  • How to render different input widgets dynamically using Conditional Builder
  • How to validate answers with regex patterns before submission
  • How to collect and save questionnaire responses to Firestore
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner6 min read20-25 minFlutterFlow Free+March 2026RapidDev Engineering Team
TL;DR

Build a questionnaire system that reads question definitions from Firestore, including input type, validation rules, and options. Render each question dynamically using Generate Dynamic Children with a Conditional Builder switching between TextField, DateTimePicker, RadioButton, and CheckboxGroup based on the inputType field. Collect all answers in a Page State Map, validate required fields and regex patterns on submit, and save responses to a questionnaire_responses collection.

Building a Dynamic Questionnaire System in FlutterFlow

Hardcoded questionnaires require an app update for every change. A dynamic system reads questions from Firestore at runtime, rendering the correct input widget for each question type. Admins can add, remove, or modify questions without touching the app. This tutorial covers schema design, dynamic rendering, validation, and response storage.

Prerequisites

  • A FlutterFlow project with Firestore configured
  • A questionnaires collection with a questions subcollection in Firestore
  • Understanding of Conditional Builder and Page State in FlutterFlow
  • Basic knowledge of regular expressions for input validation

Step-by-step guide

1

Define the questionnaire schema in Firestore

Create a questionnaires collection with fields: title (String), description (String), isActive (Boolean). Under each questionnaire, create a questions subcollection. Each question document contains: questionText (String), inputType (String: text, number, email, phone, date, singleSelect, multiSelect), options (String Array for select types), isRequired (Boolean), placeholder (String), validationRegex (String, optional), order (int). Add five to six test questions with varied input types and at least two with validation regex.

Expected result: Firestore contains a questionnaire with typed question documents including validation patterns.

2

Load questions and render dynamically with Conditional Builder

Create a QuestionnairePage with a Route Parameter questionnaireId. Add a Backend Query on the questions subcollection ordered by the order field. Add a Column with Generate Dynamic Children bound to the query results. Inside each dynamic child, use a Conditional Builder checking inputType: text and number map to TextField (number gets keyboardType number), email maps to TextField with email keyboard, phone to TextField with phone keyboard, date to DateTimePicker, singleSelect to RadioButton group populated from the options array, multiSelect to a CheckboxGroup with the options. Place the questionText as a label Text above each input.

Expected result: The questionnaire renders the correct input widget for each question based on its Firestore inputType.

3

Collect answers in a Page State Map on input change

Add a Page State variable answers (JSON type, default empty map) and a variable submitAttempted (Boolean, default false). On each input widget's On Changed callback, update the answers Map: set the key as the question document ID and the value as the entered data. For singleSelect, store the selected option string. For multiSelect, store the selected options as a list. For date, store the selected DateTime. This accumulates all responses in one structured Map for validation and submission.

Expected result: Every answer change updates the answers Map with the question ID as key and the user input as value.

4

Validate required fields and regex patterns before submission

On the Submit button tap, first set submitAttempted to true. Loop through the question documents. For each question where isRequired is true, check that answers[questionId] exists and is not empty. For questions with a validationRegex, check that the answer matches the pattern using a Custom Function that calls RegExp(regex).hasMatch(value). If any validation fails, show a SnackBar listing the first failing question. Display inline red error text below each invalid field using Conditional Visibility: show when submitAttempted is true AND the field fails validation.

validate_regex.dart
1// Custom Function: validateRegex
2bool validateRegex(String value, String regex) {
3 if (regex.isEmpty) return true;
4 return RegExp(regex).hasMatch(value);
5}

Expected result: Invalid or missing answers show red inline errors and the form does not submit until all validations pass.

5

Save the response and show completion feedback

After all validations pass, create a document in questionnaire_responses with fields: questionnaireId, userId (current user or anonymous identifier), answers (the complete Map), submittedAt (server timestamp). Show a success SnackBar or navigate to a thank-you page. Add a LinearPercentIndicator at the top of the page bound to the number of answered questions divided by total questions to show progress as the user fills in responses.

Expected result: Valid responses are saved to Firestore with a progress bar showing completion rate during filling.

Complete working example

FlutterFlow Dynamic Questionnaire Setup
1FIRESTORE DATA MODEL:
2 questionnaires/{questionnaireId}
3 title: String
4 description: String
5 isActive: Boolean
6 questions/{questionId}
7 questionText: String
8 inputType: "text" | "number" | "email" | "phone" | "date" | "singleSelect" | "multiSelect"
9 options: ["Option A", "Option B"] (select types only)
10 isRequired: Boolean
11 placeholder: String
12 validationRegex: String (optional, e.g. "^[\\w.-]+@[\\w.-]+\\.\\w+$")
13 order: int
14
15 questionnaire_responses/{responseId}
16 questionnaireId: String
17 userId: String
18 answers: Map { questionId: answer }
19 submittedAt: Timestamp
20
21PAGE STATE:
22 answers: JSON Map = {}
23 submitAttempted: Boolean = false
24
25WIDGET TREE:
26 Column (padding: 16)
27 Text (questionnaire.title, Headline Small)
28 Text (questionnaire.description, Body Medium)
29 LinearPercentIndicator (answered count / total questions)
30 SizedBox (16)
31 Column (Generate Dynamic Children questions ordered by order)
32 Per question:
33 Column
34 Text (questionText + " *" if required)
35 SizedBox (8)
36 Conditional Builder (inputType)
37 text TextField (placeholder)
38 number TextField (keyboardType: number)
39 email TextField (keyboardType: email)
40 phone TextField (keyboardType: phone)
41 date DateTimePicker
42 singleSelect RadioButton (options)
43 multiSelect CheckboxGroup (options)
44 Text (error msg, red, visible if invalid & submitAttempted)
45 SizedBox (16)
46 Button "Submit" (Primary, full width)
47 On Tap:
48 1. Set submitAttempted = true
49 2. Validate required + regex
50 3. If valid Create questionnaire_responses doc
51 4. Show SnackBar success or navigate to thank-you

Common mistakes when creating a Dynamic Questionnaire System in FlutterFlow

Why it's a problem: Not validating email and phone fields with regex before submission

How to avoid: Store a validationRegex on each question document and check it with RegExp.hasMatch before allowing submission.

Why it's a problem: Using Conditional Visibility toggles instead of Conditional Builder for input types

How to avoid: Use Conditional Builder which only builds the one matching widget, keeping the tree lean.

Why it's a problem: Hardcoding questions in the widget tree instead of loading from Firestore

How to avoid: Store all questions in Firestore and render dynamically so admins can modify questionnaires without app changes.

Best practices

  • Use order values with gaps (10, 20, 30) so new questions can be inserted between existing ones
  • Store validation regex on the question document so rules travel with the question
  • Show a progress indicator based on answered questions to encourage completion
  • Validate both required fields and regex patterns before allowing submission
  • Use Conditional Builder instead of Conditional Visibility for input type switching
  • Save anonymous user identifier when no authentication is required
  • Add placeholder text to guide users on expected input format for each field

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I want to build a dynamic questionnaire in FlutterFlow that loads questions from Firestore. Each question has an inputType (text, number, email, date, singleSelect, multiSelect) and renders the matching widget. Answers are collected in a Map, validated with regex patterns, and saved to Firestore. Show me the schema, widget tree, and validation logic.

FlutterFlow Prompt

Create a page with a title, description text, a progress bar, a scrollable list of form fields, and a submit button at the bottom.

Frequently asked questions

How do I add conditional question branching?

Add dependsOn fields to each question document (dependsOnQuestionId, dependsOnValue). In the rendering logic, check if answers[dependsOnQuestionId] matches the required value before showing the question with Conditional Visibility.

Can I paginate questions across multiple screens?

Yes. Group questions by a pageNumber field and use a PageView to navigate between pages. Show only questions matching the current page number in each view.

How do I allow users to save partial progress and resume later?

Save the current answers Map to a draft_responses collection on a Save button tap or on page dispose. On return, load the draft and pre-fill the answers Map and input widgets.

Can I export questionnaire responses to a spreadsheet?

Create a Cloud Function that queries questionnaire_responses, maps each answer Map to column headers from the questions, and generates a CSV file for download.

What regex should I use for phone number validation?

A simple pattern like ^\+?[0-9]{7,15}$ accepts international phone numbers with an optional plus prefix and 7 to 15 digits. Adjust based on your target countries.

Can RapidDev help build a questionnaire platform?

Yes. RapidDev can build complete questionnaire systems with branching logic, multi-page navigation, response analytics dashboards, and CSV export features.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.