Simple react component for building webforms. View Demo
| Feature | Description |
|---|---|
| Initial values | |
| Question Group Description | |
| Translations | |
| Multiple Question Dependency | |
| Rule based response validation | |
| Save Datapoint | |
| Computed field value | |
| Clear response | |
| Custom style | |
| Tooltip | |
| Extra component on Question | |
| HTML Support on Question | |
| Field Suffix / Prefix | |
| Download response to tabular format |
npm install --save akvo-react-formyarn add akvo-react-form| Type | Description |
|---|---|
| input | Input |
| number | InputNumber |
| cascade | Cascade Select |
| text | TextArea |
| date | Date |
| option | Option |
| multiple_option | Multiple Select |
| tree | Tree Select |
| table | Table (Multiple Question) |
| autofilled | Autofilled |
| image | Image |
import React from 'react';
import 'akvo-react-form/dist/index.css'; /* REQUIRED */
import { Webform } from 'akvo-react-form';
import * as forms from './example.json';
const App = () => {
const onChange = ({ current, values, progress }) => {
console.log(progress);
};
const onFinish = (values, refreshForm) => {
console.log(values);
};
return (
<div className="full-width">
<Webform
forms={forms.default}
onChange={onChange}
onFinish={onFinish}
/>
</div>
);
};
export default App;If using the autosave parameter, a form refresh is required to remove traces of the previous fields.
onFinish includes a function to do this, you also need to change the autosave parameter if the submission is successful. If not, the form refresh will clean up the current datapoint.
| Props | Description | Type | Default |
|---|---|---|---|
| sidebar | Option to show / hide sidebar | Boolean | true |
| sticky | Sticky header and sidebar (Not support for IE9) | Boolean | false |
| onFinish | Trigger after submitting the form and verifying data successfully | function(values) |
- |
| onChange | Trigger after field value changed | function({current,values,progress}) |
- |
| onCompleteFailed | Trigger when submit is clicked with blank required question | function(values, errorFields) |
- |
| submitButtonSetting | Submit Button Setting | Object{loading: Boolean, disabled: Boolean} | undefined |
{} |
| extraButton | Extra Button Next to Submit Button | ReactComponent | undefined |
- |
| initialValue | Set value by Form initialization | Array[Initial Value] | undefined |
Array[] |
| printConfig | Support survey print functionality | Object{showButton: Boolean, filename: String, hideInputType: Array["field type"], header: ReactComponent} | undefined |
- |
| downloadSubmissionConfig | Support download submission to Excel | Object{visible: Boolean, filename: String, horizontal: Boolean} | undefined |
- |
| leftDrawerConfig | Show left drawer with custom component | Object{visible: Boolean, title: String, Content: ReactComponent} | undefined |
- |
| autoSave | Enable auto save to IndexedDB | autoSaveObject | undefined |
- |
| fieldIcons | Show icon for input and number question type | Boolean | true |
| formRef | Set react useRef for Form from host |
React useRef |
null |
| languagesDropdownSetting | Languages Dropdown Setting | Object{showLanguageDropdown: Boolean , languageDropdownValue: ISO 639-1 codes} | undefined |
{} |
| UIText | UI localization custom param | Object{[ISO 639-1 codes]: {...translations}} | undefined |
{} |
| Props | Description | Type |
|---|---|---|
| Unique{any} | Object to be translated | Object{any} |
| language | Language | Enum[ISO 693-1] |
| Props | Description | Type |
|---|---|---|
| name | Form Name / Title | String |
| question_group | List of Question Group | Array[Question Group] |
| Unique{any} | Cascade definition, can be any properties | Array[Cascade] |
| languages | List of available languages | Array[enum[ISO 639-1]] | undefined |
| defaultLanguage | Default active language | Enum[ISO 639-1]] | undefined |
| translations | List of translations | Array[Translations] | undefined |
| Props | Description | Type |
|---|---|---|
| name | Question Group Name / Title | String |
| order | Question Group Order | Integer | undefined |
| description | Question Group Description | String | undefined |
| question | List of Question | Array[Question] |
| translations | List of translations | Array[Translations] | undefined |
Cascading select questions are sets of questions whose options depend on the response to a previous question. Cascade object should be pre-defined on the question definition root object itself.
| Props | Description | Type |
|---|---|---|
| value | Cascade Value | Unique (Integer | String) |
| label | Cascade Label | String |
| children | Children of current object | Array[Cascade] | undefined |
| translations | List of translations | Array[Translations] | undefined |
Example:
{
"name": "Community Culinary Survey 2021",
"translations": [
{
"name": "Komunitas Kuliner Survey 2021",
"language": "id"
}
],
"languages": ["en", "id"],
"question_group": [
{
"name": "Registration",
"order": 1,
"translations": [
{
"name": "Registrasi",
"language": "id"
}
],
"question": [
{
"id": 1,
"name": "Location",
"order": 1,
"type": "cascade",
"option": "administration",
"required": true,
"translations": [
{
"name": "Lokasi",
"language": "id"
}
]
}
]
}
],
"cascade": {
"administration": [
{
"value": 1,
"label": "Jawa Barat",
"children": [
{
"value": 1,
"label": "Garut"
}
]
}
]
}
}Cascading select also support for a chain API call for the cascade dropdown list.
| Props | Description | Type |
|---|---|---|
| endpoint | Cascade API | String |
| initial | Initial Parameter | Integer | String | undefined |
| list | Object name of array | res.data?.[list] | res.data | String | undefined |
Example:
"name": "Community Culinary Survey 2021",
"question_group": [{
"name": "Registration",
"order": 1,
"question": [{
"id": 1,
"name": "Location",
"order": 1,
"type": "cascade",
"api": {
"endpoint": "https://tech-consultancy.akvo.org/akvo-flow-web-api/cascade/seap/cascade-296940912-v1.sqlite/",
"initial": 0,
"list": false
},
"required": true
}]
}]| Props | Description | Type |
|---|---|---|
| id | Cascade Value | Unique (Integer | String) |
| name | Cascade Label | String |
API Example : https://tech-consultancy.akvo.org/akvo-flow-web-api/cascade/seap/cascade-296940912-v1.sqlite/0
[
{
"code": "ACEH",
"id": 47,
"name": "ACEH",
"parent": 0
},
{
"code": "BALI",
"id": 128,
"name": "BALI",
"parent": 0
}
]| Props | Description | Type |
|---|---|---|
| id | Question ID | Unique (Integer | String) |
| order | Question Order | Integer | undefined |
| tooltip | Question Tooltip | String | undefined |
| type | Question Type | number | input | text | option | multiple_option | cascade | tree | autofilled | table | image |
| option | List of Option (for option type of question ) | Array[Option] | String (cascade object name, only for 'cascade' type) | undefined |
| columns | Columns of table (for table type question) question | Array[Columns] | undefined |
| dependency | List of Question Dependency | Array[Dependency] | undefined |
| rule | Question rule to be validated (Only for 'number' type of question) | {min: Integer, max: Integer} |
| meta | Question set to be used as data point name | Boolean | undefined |
| required | Set field as required | Boolean | undefined |
| requiredSign | Set custom required field symbol/mark before question label. requiredSign content will show if required param set to true |
ReactComponent | String | undefined |
| partialRequired | Set a custom required rule for type cascade. Set true to fill without having to select all the cascade level options when the required param is true |
Boolean | undefined |
| translations | List of translations | Array[Translations] | undefined |
| extra | Extra Component | Array[ExtraComponent] | undefined |
| addonBefore | Addon before Field (only support for number and input type of question) | ReactComponent | String | undefined |
| addonAfter | Addon before Field (only support for number and input type of question) | ReactComponent | String | undefined |
| allowOther | Allow other field (support for option and multiple_option type of question) | Boolean | undefined |
| allowOtherText | Text Replacement for allow other field (support for option and multiple_option type of question) | String | undefined |
| checkStrategy | The way show selected item in box when question type is tree. Default: show checked treeNodes (just show parent treeNode), "children": show only children node | parent | children | undefined |
| expandAll | Whether to expand all treeNodes by default. Default: false |
Boolean | undefined |
| fn | Function for autofilled type of question | Autofilled Object | undefined |
| limit | Set limit / maximum file size in Megabyte (MB) for image type of question | Integer | undefined |
| Props | Description | Type |
|---|---|---|
| content | Content of the Extra Component | ReactComponent | String |
| placement | Placement for the Extra Component | before | after |
| translations | List of translations | Array[Translations] | undefined |
Rule should be defined as object, currently we only support min max value for number type of question.
| Props | Type |
|---|---|
| min | Integer | undefined |
| max | Integer | undefined |
| allowDecimal | Boolean | undefined |
Example:
{
"id": 1,
"name": "Weight",
"order": 1,
"type": "number"
"required": true,
"tooltip": {"text": "Information Text"},
"rule": {"min": 5,"max": 10},
"addonAfter": "Kilograms",
"meta": true,
"translations": [{
"name": "Berat Badan",
"language": "id"
}
],
"extra": [{
"placement": "before",
"content": "Extra Component before the question",
"translations": [{
"content": "Komponen Tambahan sebelum pertanyaan ini",
"language": "id"
}]
}]
}If question has dependency, question will be hidden by default. The question will only shows when dependency question values matches with the dependency rules.
| Props | Description | Type |
|---|---|---|
| id | Question ID | Integer | String |
| options | List of dependency options to be validated, for 'option' type of the dependency question | Array[String] | undefined |
| min | Minimum dependency value to be validate, for 'number' type of the dependency question | Array[String] | undefined |
| max | Maximum dependency value to be validate, for 'number' type of the dependency question | Array[String] | undefined |
| equal | Dependent answer is equal to | Integer | String | undefined |
| notEqual | Dependent answer is not blank and not equal to | Integer | String | undefined |
Example:
{
"id": 11,
"name": "Where do you usually order Rendang from ?",
"dependency": [
{
"id": 9,
"options": ["Yes"]
},
{
"id": 10,
"min": 8
}
],
"order": 5,
"type": "option",
"option": [
{
"name": "Pagi Sore",
"order": 1
},
{
"name": "Any Rendang Restaurant",
"order": 2,
"translations": [
{
"name": "Restoran Rendang Manapun",
"language": "id"
}
]
}
],
"required": true,
"translations": [
{
"name": "Dimana anda biasanya membeli Rendang?",
"language": "id"
}
]
}Option is valid only for option type of question
| Props | Description | Type |
|---|---|---|
| name | Option Name / Label | String |
| order | Question Group Order | Integer | undefined |
| translations | List of translations | Array[Translations] | undefined |
Columns is valid only for table type of question
| Props | Description | Type |
|---|---|---|
| name | Column / Question object key | String |
| type | Column / Question Type | number | input | text | option |
| label | Column / Question Label | String |
| option | Option value | Array[Option] | undefined |
| Props | Description | Type |
|---|---|---|
| question | Question ID | Unique (Integer | String) |
| value | Value of the Question | String | Integer | Object{lat,lng} | Array[Integer | String] | Date Format |
| repeatIndex | Repeat Index in Repeated Question Group. Default: 0 | Integer | undefined |
Example: Initial Value Example
| Props | Description | Type |
|---|---|---|
| fnString | String of function | String |
| multiline | Wether function is multiline or not | Bool | undefined |
Example for fnString:
function () { return #1 / #2 }OR
() => { return #1.includes("Test") ? #2 / #3 : 0 }Prefix #N is use to indicate the value of question id N. Note that we don't use javascript eval to overcome the security issue, the function will be sanitized before it's executed.
| Props | Description | Type |
|---|---|---|
| formId | Required | Integer |
| name | Name for datapoint | String | undefined |
| buttonText | Custom text for save button | String | undefined |
Auto save object require formId when it's enabled. This will filter list of saved data for particular formId. To show the list of saved datapoint we can use dataStore.
Example:
import React, { useState, useEffect } from 'react'
import { dataStore } from 'akvo-react-form'
const DataList = () => {
const [datapoint, setDatapoint] = useState([])
useEffect(() => {
const listData = dataStore.list(formId)
listData.then((x) => {
setDatapoint(x)
})
}, [])
return (
<table>{dataPoints.map((x, xi) => (
<tr key={xi}>
<td>
{xi + 1}. {x.name}
</td>
<td>
<button onClick={x.load}>
Load
</button>
<button onClick={x.remove}>
Delete
</button>
</Space>
</td>
</tr>
))}
</table>)
}Please check the Form Definition Example which contains all the current features of akvo-react-form.
AGPL-3.0 © akvo