Native surveys built from declarative definitions (JSON). Many question types, skip logic etc.
- Displays a single question at a time, but allow the user to scroll up to read and change previous answers.
- Takes input from a JSON file.
- Many supported question types, including single selection, multiple selection, single text field, additive text fields, segment choice, year picker, date picker, and table-style questions.
- Support for sub-questions.
- Support for showing/hiding questions based on previous answers.
The expected input is an array of questions
and a submit
object, detailing how to submit the answers.
-
id
(String): Required. Used to key answer. Also used to check show/hide conditions. -
header
(String): Optional. Displayed as section header. -
question
(String): Required. Text to display for question. -
question_type
(String): Required. The chosen type may require additional keys.single_select
screenshot | jsonmulti_select
screenshot | jsonyear_picker
screenshot | jsondate_picker
screenshot | jsonsingle_text_field
screenshot | jsonmulti_text_field
screenshot | jsondynamic_label_text_field
screenshot | jsonadd_text_field
screenshot | jsonsegment_select
screenshot | jsontable_select
screenshot | json
-
sub_questions
(Array of questions): Optional. Expected keys in each question are the same as a top-level question, except that header is not required (or shown if provided). Normally, a sub-question would have ashow_if
key, but it's not required. Theshow_if
section of a sub-question may refer to previous sub-question answers. -
show_if
(Conditions): Optional. If not provided, the question will default to being shown. See the Structure for Show/Hide question below for more info.
-
options
(Array of Strings or Other object): Required forsingle_select
,mult_select
,table_select
question_types. Thetable_select
does not support the Other object. The Other object is a JSON object with a key fortitle
. When selected, the user may enter text into a text field. -
label
(String): Optional forsingle_text_field
question type. -
label_options
(Array containing Strings or String Arrays): Required fordynamic_label_text_field
. -
input_type
(String): Optional forsingle_text_field
,dynamic_label_text_field
,add_text_field
question_types. Can be set tonumber
to change the default keyboard to the number keyboard for the text field(s). -
max_chars
(String): Options forsingle_text_field
andmulti_text_field
question_types. Determines the max number of characters the user may enter. -
validations
(Array of Dictionaries): Optional forsingle_text_field
anddynamic_label_text_field
question_types. Check value meets the validations whenNext
tapped. If notvalidationFailed(message: String)
is called on yourValidationFailedDelegate
. Validations consist of attributes:operation
value
oranswer_to_question_id
on_fail_message
for_label
(only used fordynamic_label_text_field
)
Supported operations:
equals
not equals
greater than
greater than or equal to
less than
less than or equal to
-
values
(Array of String): Required forsegment_select
question_type. These are the values the user will choose between. -
fields
(Array of Dictionaries): Required formulti_text_field
question_type. Each dictionary must contain alabel
key and aninput_type
key. -
low_tag
(String): Optional forsegment_select
question_type. This is a label for the lowest (first) value. -
high_tag
(String): Optional forsegment_select
question_type. This is a label for the highest (last) value. -
table_questions
(Array of table questions): Required fortable_select
question_type. Each table question should have atitle
and anid
attribute. -
min_year
(String): Optional foryear_picker
question_type. Can be an integer or "current_year". See More about Year Picker below for more info. -
max_year
(String): Optional foryear_picker
question_type. Can be an integer or "current_year". See More about Year Picker below for more info. -
num_years
(String): Optional foryear_picker
question_type. See More about Year Picker below for more info. -
initial_year
(String): Optional foryear_picker
question_type. If set, this year will be selected when the picker is first opened. -
sort_order
(String): Optional foryear_picker
question_type. May be "ASC" (ascending) or "DESC" (descending). Defaults to "ASC". -
date
(String in YYYY-MM-dd format or "current_date"): Optional fordate_picker
question_type. If specified, the picker will initially be set to this value (unless the question is already answered, in which case it will be set to the previous answer). If unset, defaults to the current date. -
max_date
(String in YYYY-MM-dd format or "current_date"): Optional fordate_picker
question_type. If specified, the picker will not allow the user to choose a date later than this. If min_date is specified and min_date > max_date, both values will be ignored. -
min_date
(String in YYYY-MM-dd format or "current_date"): Optional fordate_picker
question_type. If specified, the picker will not allow the user to choose a date earlier than this. If min_date is specified and min_date > max_date, both values will be ignored. -
date_diff
(Dictionary of String to Int values): Optional fordate_picker
question_type. Valid keys areday
,month
, andyear
. Only takes effect if exactly one ofmin_date
andmax_date
is set. The unset min/max value will be set by adding the affect of this to the set min/max value.date_diff
should be overall positive ifmin_date
is set and negative ifmax_date
is set. Ifdate_diff
is set such thatmin_date
>max_date
, both values will be ignored.
You only need to specify two of min_year
, max_year
, and num_years
. The missing values will be calculated from what is provided. If all three are provided, the num_years
value will be ignored. If less than two values are provided, we'll guess reasonable values for the missing ones.
Whether a question is shown or hidden is dependent on the show_if
key. If the key is missing, the default is to show the question. Both simple conditions and decision trees are supported. The decision trees can contain other decision trees, so you can have fairly complicated logic. There is probably some limit to how far you can nest them.
-
id
(String): Required. This is the id for a question. -
subid
(String): Optional. This allows access to answers totable_select
questions to be used, or any other answer that's within a dictionariy. -
operation
(String): Required. Supported operations:equals
not equals
greater than
greater than or equal to
less than
less than or equal to
contains
not contains
-
value
(Any): Required. This is the value to compare the answer to.
-
operation
(String): Required. Can beor
orand
. If you need a combination, you should be able to use nesting to get it. -
subconditions
(Array of Simple Conditions or Decision Trees): Required.
If these options are inadequate, you can set a CustomConditionDelegate and use it to make the show/hide decision.
-
ids
(Array of Strings): Required. Must be non-empty. These are the ids for questions the your delegate needs the answers to in order to perform it's show/hide calculation. Your delegate will be called as soon as any of the questions are answered, so you may have nil data for one or more answers. -
operation
(String): Required. Should be set to 'custom'. -
extra
(Dictionary with String keys): Optional. This will be passed to the isConditionMet method of your CustomConditionDelegate.
The submit object (a peer to questions
) requires only two keys, button_title
and url
. Both are required strings.
{
"id": "ice_cream",
"header": "Question 1",
"question": "What is your favorite ice cream flavor?",
"question_type": "single_select",
"options": [
"Strawberry",
"Chocolate",
"Vanilla",
{
"title": "Other",
"type": "freeform"
}
]
}
{
"id": "music_types",
"header": "Question 6",
"question": "What types of music do you like?",
"question_type": "multi_select",
"options": [
"Pop",
"Rock",
"Rap",
"Country",
{
"title": "Other",
"type": "freeform"
}
]
}
{
"id": "birthyear",
"header": "Question 2",
"question": "Enter the year of your birth.",
"question_type": "year_picker"
"max_year" : "current_year",
"num_years" : "125",
"sort_order" : "DESC"
}
{
"id": "date",
"header": "Question 11",
"question": "What is was the best day of the last year?",
"question_type": "date_picker",
"date" : "current_date",
"max_date" : "current_date",
"date_diff" : { "year" : -1 },
}
{
"id": "age",
"header": "Question 4",
"question": "What is your current age in years?",
"question_type": "single_text_field",
"label": "Years",
"input_type": "number",
"max_chars": "2",
"validations": [
{
"operation": "greater than",
"value": 10,
"on_fail_message": "Age must be at least 10"
},
{
"operation": "less than",
"value": 80,
"on_fail_message": "You must be 80 or younger"
}
]
}
{
"id":"pets",
"header": "Question 12",
"question": "How many pets do you have?",
"question_type": "multi_text_field",
"fields": [
{
"label" : "Dogs",
"input_type" : "number"
},
{
"label" : "Cats",
"input_type" : "number"
}
]
}
{
"id": "height",
"header": "Question 7",
"question": "How tall are you?",
"question_type": "dynamic_label_text_field",
"label_options": [
[
"Feet",
"Inches"
],
"Centimeters"
],
"options_metadata": {
"id": "unit_system",
"types": [
"imperial",
"metric"
]
},
"input_type": "number",
"validations": [
{
"for_label": "Feet",
"operation": "greater than",
"value": 3,
"on_fail_message": "Height must be at least 4 feet"
},
{
"for_label": "Feet",
"operation": "less than",
"value": 10,
"on_fail_message": "Height must be less than 10 feet"
},
{
"for_label": "Centimeters",
"operation": "greater than",
"value": 100,
"on_fail_message": "Height must be at least 100cm"
},
{
"for_label": "Centimeters",
"operation": "less than",
"value": 250,
"on_fail_message": "Height must be less than 250cm"
}
]
}
{
"id": "which_sports",
"question": "Which sports do you like to play?",
"question_type": "add_text_field",
"input_type": "default"
}
{
"id": "happiness",
"header": "Question 8",
"question": "How happy are you?",
"question_type": "segment_select",
"low_tag": "Not happy",
"high_tag": "Super happy",
"values": [
"1",
"2",
"3",
"4",
"5",
"6",
"7"
]
}
{
"id": "weekend_activities",
"header": "Question 9",
"question": "On the weekends, do you:",
"question_type": "table_select",
"options": [
"Yes",
"Sometimes",
"No"
],
"table_questions": [
{
"title": "Play sports?",
"id": "play_sports"
},
{
"title": "Read books?",
"id": "read_books"
},
{
"title": "Go dancing",
"id": "go_dancing"
},
{
"title": "Watch TV and movies?",
"id": "watch_tv"
}
]
}
Areas we'd love to see contributions:
- Bug fixes
- Support for
optional
boolean flag on every question type that adds a skip button. - New question types
- Customizable styling
- Customizable animation
- Dynamic question number substitution in header
- Option to enable/disable animations
- Android Port
- Export qualtrics/survey-monkey surveys to SurveyNative
- CareKit/ResearchKit integration