NextJs & SurveyJS
If you got into a situation when you have to build a very complex survey application, you will find yourself looking for solutions that help you get a great result without building the entire thing from scratch.
If you google this you might get multiple solutions that might help you, like Typeform, but you'll get limited either by the pricing or but the limitation of option it provides.
One of the solutions you will get is a library called SurveyJs.
The SurveyJs issues with NextJs
One of the main issues that encounter many developers is that SurveyJs is a Browser-side library and on the other hand NextJs is using server-side rendering or static generation.
Installations
- Install SurveyJs
yarn add survey-react
- Create a new file named
survey.tsx
underpages
import dynamic from "next/dynamic"
import styled from "styled-components"
const SurveyComponent = dynamic(() => import("../components/survey"), {
ssr: false,
})
const Container = styled.div`
margin: 2rem;
`
const Survey = () => {
return (
<Container>
<SurveyComponent />
</Container>
)
}
export default Survey
As you notice we used dynamic import with ssr: false
option provided by Nextjs
to make sure our SurveyComponent
is not included on server-side
.
Read more about dynamic imports from Nextjs here.
- Create the
SurveyComponent
// components/survey/index.tsx
import * as Survey from "survey-react" // import surveyjs
import { questions } from "./content" // these are the survey questions
import { Container } from "./styles" // your styles here
// Modern theme
import "survey-react/modern.min.css"
// Default theme
// import 'survey-react/survey.min.css';
const SurveyComponent = () => {
// Apply theme
Survey.StylesManager.applyTheme("modern")
// Create a modal
const survey = new Survey.Model(questions)
// Render the survey
return (
<Container className="container">
<Survey.Survey model={survey} />
</Container>
)
}
export default SurveyComponent
- Create the file containing the survey
questions
// components/survey/content/index.tsx
export const questions = {
showQuestionNumbers: "off",
pages: [
{
name: "page1",
elements: [
{
type: "text",
name: "name",
title: "Name",
isRequired: true,
},
],
},
],
}
Question types
SurveyJs provide a variety of question types I will try to mention some.
- Radio
{
type: "radiogroup",
name: "free_registered_user",
title: "Question 1",
isRequired: true,
description: "Would you like to become a free registered user",
choices: ["Yes", "No"],
}
- Dropdown
// using static data as choices
{
type: "dropdown",
name: "region",
title: "Region",
choices: ["Africa", "Americas", "Asia", "Europe", "Oceania"],
},
// using API data as choices
{
type: "dropdown",
name: "region",
title: "Region",
isRequired: true,
choicesByUrl: {
url: "URL_API_HERE", // external API
url: "/api/region", // Next API
},
},
- Percentages
{
type: "text",
name: "percentage",
title: "Some percentage",
isRequired: true,
inputType: "number",
min: 0,
max: 100,
},
- Checkbox
{
type: "checkbox",
name: "checkbox",
title: "Some checkbox",
// isRequired: true,
choices: [
"Option 1",
"Option 2",
"Option 3",
"Option 4",
"Option 5",
],
},
Widgets
There are also many widgets that you can use. You will find the list of widgets here.
But first to be able to work with these widgets you need to: install surveyjs-widgets
yarn add surveyjs-widgets
Since they don't support TypScript yet, you will need to create a file named
surveyjs-widgets.d.ts
and include this line in it.
declare module 'surveyjs-widgets';
- Import
widgets
in theSurveyComponent
import * as widgets from "surveyjs-widgets"
- Import widget styles in our example we will use
nouislider
import "nouislider/distribute/nouislider.min.css"
- And finally, add this inside
SurveyComponent
widgets.nouislider(Survey)
After that, you can simply add the questions as type: nouislider
, and this works for all other widgets.
{
type: "nouislider",
name: "slidePercentage",
title:
"Some %",
// isRequired: true,
rangeMin: 0,
rangeMax: 1000,
// You can install and use the wnumb to customize tooltip numbers like this
tooltips: wNumb({
decimals: 0,
}),
},
Passing question value to other questions
This is very easy just like in the example below:
{
type: "dropdown",
name: "region",
title: "Region",
choices: ["Africa", "Americas", "Asia", "Europe", "Oceania"],
},
{
type: "dropdown",
name: "country",
title: "Country",
choicesByUrl: {
url: "https://restcountries.eu/rest/v2/region/{region}",
valueName: "name",
},
},
The same goes for other question properties like:
visibleIf: "{number} > 4"
Save survey state to local storage
To prevent losing questions answers on page reload SurveyJs
provides a way of doing it, by saving survey data in local storage.
You can call this inside your SurveyComponent
// /components/survey/index.tsx
survey.sendResultOnPageNext = true
const storageName = "SurveyNextjs"
function saveSurveyData(survey: any) {
let data = survey.data
data.pageNo = survey.currentPageNo
window.localStorage.setItem(storageName, JSON.stringify(data))
console.log(data)
}
survey.onPartialSend.add(function (survey) {
saveSurveyData(survey)
})
const prevData = window.localStorage.getItem(storageName) || null
if (prevData) {
let data = JSON.parse(prevData)
survey.data = data
if (data.pageNo) {
survey.currentPageNo = data.pageNo
}
}
Save data on survey complete
survey.onComplete.add(function (survey, options) {
saveSurveyData(survey)
console.log(survey.data)
// window.location.href = "/survey/finish";
})
I hope you found that interesting, informative, and entertaining. I would be more than happy to hear your remarks and thoughts about this solution.
If you think other people should read this post. Tweet, share and Follow me on Twitter for the next articles.