SurveyJS for Flutter (surveyjs_flutter)
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
- Supported Question Types
- Installation
- Android Setup (Important)
- Usage
- Example App
- Requirements
- Dependencies
- License
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:
- Add the
jitpackrepository toandroid/build.gradle(orandroid/settings.gradle):
allprojects {
repositories {
google()
mavenCentral()
maven { url "https://jitpack.io" }
}
}
- 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
flutter_js— JavaScript runtime for SurveyJS Core enginefile_picker— File upload selectionimage_picker— Camera capture and photo selectionsignature— Signature drawing canvasmime— MIME type detection
License
This package is licensed under the MIT License.
Libraries
- surveyjs_flutter
- Flutter SurveyJS - A Flutter package for rendering SurveyJS forms