Surveys are a great way to gather the information you need to better satisfy your user base, and then break that data down into whatever easily trackable indices you need ā for patterns that your stakeholders will find useful, or just for internal monitoring over time.
SurveyJS is a free and open-source (FOSS) JavaScript library that lets you do all of that ā but goes one step further ā using a dynamic, data-driven approach using industry-standard JSON as common ground: you define your surveys as JSON data models (āschemasā) and build form UI elements from templates that use said data models.
But hereās what will *really *blow your mind.
SurveyJS lets you go all-in on dynamicity, and have any values be populated from a REST API. Your data sources can be defined in the schema itself, via the choicesByUrl property. Say goodbye to code bloat resulting from lines of asynchronous XMLHttpRequests!
The Demo
To demonstrate just how much convenience this brings to *anyone *designing surveys, letās build a food habits survey for a fictitious restaurant that needs to gauge favorite foods and service expectations from a potential customer base.
This example will serve as a great starting point for your own surveys in nutritional counseling, market research for restaurants and fast food joints, or for just observing differences in attitudes when it comes to people dining out.
Getting Started
First off, install the SurveyJS client-side libraries for your framework of choice ā React, Angular, Vue.js, Knockout ā or follow these instructions here for **jQuery **if you donāt use a framework. Weāre using React for our code example.
Now, hereās the game plan:
-
Weāll use SurveyJSā feature of populating choices from a RESTful service,
-
Utilizing two REST APIs, the RESTCountries API, and TheMealDB API. Both have a free, public tier that doesnāt need authentication.
-
A survey for a restaurant that aims to be a hot, happening, cultural center needs to reflect that same energy. So weāll use extensive customization with CSS to turn our utilitarian-looking survey intoā¦.this!
Before and After.
But Firstā¦Getting Some REST.
Before we start, letās quickly look at how SurveyJS RESTful service works using two test cases ā the two APIs weāll be using. One, for geolocation, the popular RESTCountries API, and two, for our main use-case, TheMealDB API.
First, geolocation. The response format for this specific REST API is like this:
[
{
"name": {
"common": "Australia",
"official": "Commonwealth of Australia",
"nativeName": {
"eng": {
"official": "Commonwealth of Australia",
"common": "Australia"
}
}
}
}
]
If we wanted the common name of the country, āAustraliaā, weād access this property in this JSON object with name.common.
So in our schema, weāll just define our data source in the choicesByUrl property, specifying valueName to access data like so:
{
"elements": [
{
"type": "dropdown",
"name": "country",
"title": "Select a country",
"isRequired": true,
"choicesByUrl": {
"url": "https://restcountries.com/v3.1/all?fields=name",
"valueName": "name.common"
}
}
]
}
Simple enough, right? But what if our top-level property was an array instead of a standard JSON object? How do we define this in our survey schema? We clearly canāt do meals.strArea, as we can see in our second API example here:
{
"meals": [
{
"strArea": "American"
},
{
"strArea": "British"
},
{
"strArea": "Canadian"
},
{
"strArea": "Chinese"
}
]
}
Thatās where the path property comes in!
{
"elements": [
{
"type": "dropdown",
"name": "question4",
"title": "What's your favorite cuisine?",
"isRequired": true,
"choicesByUrl": {
"url": "https://www.themealdb.com/api/json/v1/1/list.php?a=list",
"path": "meals",
"valueName": "strArea"
}
}
]
}
Together with valueName, you can access any data within a REST APIās response.
Finally, weāre using SurveyJS' ImagePicker field type, which populates a grid of images to choose from ā said choices coming from a REST API, of course. In addition to path, and valueName, here are the final properties youāll come across while writing this schema ā titleName, and imageLinkName. They work the exact same way in principle; you specify the properties in the response JSON object that includes the title for that image, and the actual image URL, respectively.
{
"meals": [
{
"strMeal": "Krispy Kreme Donut",
"strMealThumb": "https://www.themealdb.com/images/media/meals/4i5cnx1587672171.jpg",
"idMeal": "53015"
}
]
}
Our API response format for this has the image title in strMeal and image URL in strMealThumb, soā¦
{
"type": "imagepicker",
"name": "question6",
"title": "What's a dessert you'd always order? Feel free to skip if you don't usually order these.",
"choicesByUrl": {
"url": "https://www.themealdb.com/api/json/v1/1/filter.php?c=Dessert",
"path": "meals",
"titleName": "strMeal",
"imageLinkName": "strMealThumb"
},
"showLabel": true
}
ā¦those are our required values for titleName and imageLinkName, respectively.
On To The Fun Stuff!
Got all of that? Good. Letās get to coding.
1. The Survey Schema
Weāve got 9 questions across multiple pages, some of which populate choices from the REST APIs weāve just talked about. There are some other things going on here that merit a second look:
-
Custom Variables. You can store responses to each question (including Question 9 ā which asks respondents to drag-and-drop to arrange facets of service in order of importance) in JSON variables, and use them wherever ā and however ā in the survey you want. This could be used to determine subsequent question strings (as in Question 4, which uses Question 3ās answer), logic, and yes ā even other REST API calls!
-
Conditional Logic. Question 2 (country) is hidden and only pops in if a value in Question 1 (region) has been picked.
-
Dynamic HTML generation on-the-fly post-survey completion, using the top-level completedHtml property. Weāre using it here to show chosen answers in a , but you could even use logic to determine HTML conditionally via the completedHtmlOnCondition property ā generating markup based on answers!
Whatās more, if you wanted to, you could even use conditional logic to do dynamic redirects to URLs based on certain answers! For example, sending the respondent to your company siteās regional subdomain depending on which region they picked.
ānavigateToUrlOnConditionā: [
{
āexpressionā: ā{question1} = āasiaāā,
āurlā: āhttps://yourcompanysite.com/region/asia"
}
]
2. The React App
Nothing special here. We import the schema (in a real-world example, youād retrieve this from a proxy server serving as your backend), then use it to generate a survey using components in SurveyJSā React library.
You have your survey answers in JSON format in the onComplete trigger, and you can use it to do whatever you want post-survey completion. Whether thatās sending HTTP POST requests with it as payload to trigger custom behavior off-site (i.e. a webhook), saving it to a database, or creating visualizations on-the-fly using it; go wild.
Weāve also got some basic XSS protection here via Reactās default data binding (curly braces).
Finally, hereās our CSS:
Go ahead and read up this particular section in SurveyJS documentation to know which CSS classes you can override with your custom CSS.
Hereās how our buttons work, for example:
const surveyCss = {
actionBar: {
root: "sd-action-bar custom-actionbar-root",
},
navigation: {
complete: "sd-btn--action sd-navigation__complete-btn custom-btn",
prev: "sd-navigation__prev-btn custom-btn",
next: "sd-navigation__next-btn custom-btn",
start: "sd-navigation__start-btn custom-btn",
preview: "sd-navigation__preview-btn custom-btn",
},
};
return (
<div>
<Survey model={survey} css={surveyCss} />
</div>
);
.custom-actionbar-root {
display: flex;
align-items: center;
justify-content: center;
}
.custom-btn {
background-color: var(--color-btn);
color: var(--color-cultured);
border-radius: 30px;
font-family: var(--font-body-2);
font-size: 1.5rem;
font-weight: 100;
transition: 700ms;
}
.custom-btn:not(:disabled):hover,
.custom-btn:not(:disabled):focus {
/* glow here */
box-shadow: var(--box-shadow-blue-glow);
}
Cause and Effect.
A Dynamic, āBuilding Blocksā Approach
And thatās all, folks! Hopefully, now you have a pretty decent idea of how to create awesome-looking, flexible, dynamic surveys without breaking the bank for custom widget libraries, or rolling your own HTML/CSS/JS for bespoke solutions that do not scale, and drain company resources to create, update, and maintain.
So using SurveyJS, weāve made sure that:
-
You are not tied down to the technology stack between used; JavaScript, Python, etc. with no room for flexibility if technical requirements change. JSON and REST are *universal *data interchange formats/standards ā use whatever frontend, server, or database tech stack you want.
-
You can make quick changes and additions to your surveys regardless of technical expertise, as JSON is well-structured, easy-to-understand, and editing it is just like editing a text file.
-
You can customize your surveys visually as you see fit now that your design layer is entirely decoupled from the data and logic. Get creative with fully custom styling ā whether thatās CSS, SCSS, CSS-in-JS, whichever fits your use case ā or use one of the many themes that ship with SurveyJS.
Thatās what makes it so powerful. Itās an elegant, loosely-coupled, building-blocks approach to survey/form creation that brings scalability, and simplifies code maintenance.