SurveyJS for Flutter (surveyjs_flutter)

pub package License: MIT

A Flutter package for rendering SurveyJS forms natively in Flutter applications. Powered by the official SurveyJS Core JavaScript engine, this package provides dynamic form rendering, conditional logic evaluation, 19+ question types, custom themes, validation, and multi-page navigation.


Table of Contents


Features

  • Full SurveyJS Core Engine — Renders official SurveyJS JSON definitions natively in Flutter.
  • Dynamic UI Generation — Form widgets are automatically instantiated and updated from JSON.
  • 19+ Question Types — Text, Radiogroup, Checkbox, Dropdown, Rating, Slider, Matrix, File Upload, Signature, and more.
  • Custom Question Widgets — Easily register your own Flutter widgets for custom question types.
  • Conditional Logic & Expressions — Full support for SurveyJS visibleIf, enableIf, requiredIf, calculated values, and built-in functions.
  • Built-in Validation — Real-time validation with custom error messages and focus propagation.
  • Multi-Page & TOC Navigation — Navigate between survey pages with optional Table of Contents drawer.
  • Customizable Theming — Built-in Light & Dark presets, plus custom font, color, and spacing overrides.
  • Media & Inputs — Supports image pickers, file attachments, signature pads, HTML text, and rating scales.
  • Cross-Platform — Runs on iOS, Android, and Web.

Supported Question Types

Category Question Types Description
Basic Inputs text, comment, radiogroup, checkbox, dropdown, boolean, rating Core form controls including text fields, textareas, choices, toggles, and rating bars.
Advanced Controls matrix, slider, tagbox, ranking, multipletext Choice matrices, range sliders, multi-select tag chips, drag-and-drop ranking, and multi-field inputs.
Media & Special file, imagepicker, signaturepad, html, expression File attachments, image pickers, signature drawing canvas, raw HTML blocks, and dynamic calculations.
Complex Containers matrixdropdown, matrixdynamic, paneldynamic Cell-configurable matrices, dynamic add/remove matrix rows, and template-based dynamic panels.

Installation

Add surveyjs_flutter to your pubspec.yaml:

dependencies:
  surveyjs_flutter: ^0.1.0

Then run:

flutter pub get

Android Setup (Important)

Due to the complex nature of SurveyJS traversing UI observables, the default QuickJS engine on Android can cause high CPU overhead on complex forms. This package utilizes JavaScriptCore on Android for JIT-accelerated JavaScript evaluation identical to iOS.

To enable this engine safely, link the JavaScriptCore native binary in your Android project:

  1. Add the jitpack repository to android/build.gradle (or android/settings.gradle):
allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url "https://jitpack.io" }
    }
}
  1. Add the native runtime dependency to android/app/build.gradle:
dependencies {
    implementation "com.github.fast-development.android-js-runtimes:fastdev-jsruntimes-jsc:0.3.4"
}

Usage

Basic Example

import 'package:flutter/material.dart';
import 'package:surveyjs_flutter/surveyjs_flutter.dart';

class MySurveyPage extends StatelessWidget {
  const MySurveyPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Customer Survey')),
      body: SurveyScreen(
        config: SurveyConfig(
          surveyJson: {
            "title": "Customer Satisfaction Survey",
            "pages": [
              {
                "name": "page1",
                "elements": [
                  {
                    "type": "rating",
                    "name": "satisfaction",
                    "title": "How satisfied are you with our service?",
                    "isRequired": true,
                    "rateMin": 1,
                    "rateMax": 5,
                  },
                  {
                    "type": "comment",
                    "name": "feedback",
                    "title": "Additional feedback",
                  },
                ],
              }
            ],
          },
          onComplete: (result) {
            debugPrint('Survey completed!');
            debugPrint('Results: ${result.data}');
          },
          onValueChanged: (questionName, value) {
            debugPrint('$questionName changed to: $value');
          },
        ),
      ),
    );
  }
}

With Custom Theme

SurveyScreen(
  config: SurveyConfig(
    surveyJson: mySurveyJson,
    themePreset: SurveyThemePreset.dark,
    theme: const SurveyTheme(
      primaryColor: Colors.teal,
      errorColor: Colors.redAccent,
      questionTitleStyle: TextStyle(
        fontSize: 18,
        fontWeight: FontWeight.bold,
      ),
    ),
    onComplete: (result) {
      // Handle completion
    },
  ),
)

Accessing Survey Results

onComplete: (SurveyResult result) {
  // Get all survey response data
  final allData = result.data;
  
  // Get specific question answer
  final satisfaction = result.getValue('satisfaction');
  
  // Check if a question was answered
  if (result.hasAnswer('feedback')) {
    debugPrint('User provided feedback: ${result.getValue('feedback')}');
  }
  
  // Export full snapshot JSON (includes data, state, and metadata)
  final snapshot = result.toSnapshotJson();
}

Advanced Usage

Custom Question Types

You can register custom Flutter widgets for custom question type names defined in your SurveyJS JSON:

// 1. Define your custom question widget
class ColorPickerWidget extends StatelessWidget {
  final Map<String, dynamic> question;
  final ValueChanged<dynamic> onChanged;
  
  const ColorPickerWidget({
    super.key,
    required this.question,
    required this.onChanged,
  });
  
  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(question['title'] ?? 'Pick a color'),
        ElevatedButton(
          onPressed: () => onChanged('#FF0000'),
          child: const Text('Select Red'),
        ),
      ],
    );
  }
}

// 2. Register globally via QuestionFactory
QuestionFactory.register('colorpicker', (context, question, onChanged) {
  return ColorPickerWidget(question: question, onChanged: onChanged);
});

// 3. Or pass custom builders scoped to a single SurveyScreen
SurveyScreen(
  config: SurveyConfig(
    surveyJson: mySurveyJson,
    customBuilders: {
      'colorpicker': (context, question, onChanged) => ColorPickerWidget(
        question: question,
        onChanged: onChanged,
      ),
    },
  ),
)

JSON Validation

By default, the package validates the survey JSON structure before initialization to catch schema errors early:

SurveyScreen(
  config: SurveyConfig(
    surveyJson: mySurveyJson,
    // Disable automatic pre-validation if needed
    validateJson: false,
    // Handle validation errors manually
    onValidationError: (errors) {
      debugPrint('Validation failed: $errors');
    },
  ),
)

Example App

Check out the /example directory for a complete demo application showcasing:

  • Simple Customer Feedback Survey
  • All Question Types Showcase
  • Choice Questions & Dropdowns
  • Single & Dynamic Matrix Questions
  • Media & Signature Capture
  • Logic & Expression Evaluations

Run the example app:

cd example
flutter run

Requirements

  • Flutter SDK: >=3.10.0
  • Dart SDK: >=3.0.0

Dependencies


License

This package is licensed under the MIT License.

Libraries

surveyjs_flutter
Flutter SurveyJS - A Flutter package for rendering SurveyJS forms