Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/indix/formland
A simple, super-flexible, extensible config based form generator for React.
https://github.com/indix/formland
form-generator react react-forms
Last synced: about 1 month ago
JSON representation
A simple, super-flexible, extensible config based form generator for React.
- Host: GitHub
- URL: https://github.com/indix/formland
- Owner: indix
- License: mit
- Created: 2017-12-01T03:38:51.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2019-07-22T04:31:47.000Z (over 5 years ago)
- Last Synced: 2024-10-31T18:38:25.688Z (about 1 month ago)
- Topics: form-generator, react, react-forms
- Language: TypeScript
- Homepage: https://oss.indix.com/formland/
- Size: 1.05 MB
- Stars: 33
- Watchers: 3
- Forks: 10
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-react - formland - A simple, super-flexible, extensible config based form generator
README
![Logo](https://image.ibb.co/iF9Doe/formland.png)
[![Build Status](https://travis-ci.org/indix/formland.svg?branch=master)](https://travis-ci.org/indix/formland)
[![npm version](https://badge.fury.io/js/formland.svg)](https://badge.fury.io/js/formland)A simple, super-flexible, extensible config based form generator for React.
## Features
* Super-flexible
* Config based form element creation
* Take super control over all the form elements
* Use third party components as form element## Install
```bash
npm i formland# or
yarn add formland
```## Usage
```javascript
import 'formland/css/index.css'
import React, { Component } from 'react'
import Form from 'formland'class Example extends Component {
constructor() {
super()
this.state = {}
this.onChange = this.onChange.bind(this)
}onChange(newState) {
this.setState(newState)
}render() {
const config = [
{
id: 'firstName',
type: 'text',
displayName: 'First Name',
resultPath: 'name.firstName',
placeholder: 'Enter your first name',
},
]return
}
}
```## Props
| Property | Type | Default | Description |
| ------------------------ | ---------------------------- | --------- | ------------------------------------------------------------------- |
| config | array | [] | Config to populate form elements. |
| store | object \| array | {} | The data store to read the values from. |
| onChange | function | undefined | Callback for `onChange` event |
| onBlur | function | undefined | Callback for `onBlur` event |
| onFocus | function | undefined | Callback fro `onFocus` event |
| customComponentResolvers | array | undefined | Array of resolvers to resolve custom form elements |
| customValueResolvers | array | undefined | Array of resolvers to resolve the value of the custom form elements |
| useNativeEvent | boolean | false | Whether to return the new state or native JS event object on events |
| primaryButton | string \| false \| undefined | 'Submit' | Title for the primary button. `false` to remove button |
| secondaryButton | string \| false \| undefined | 'Cancel' | Title for the secondary button. `false` to remove button |
| onSecondaryButtonClick | function | `()=> {}` | onClick event handler for secondary button |## Configuration File Properties
| Property | Type | Default | Description |
| ----------------------- | -------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | string | undefined | ID for each form field. This should be unique. |
| type | string | undefined | Type of the form field to be generated. The native package supports `text`, `color`, `date`, `email`, `month`, `number`, `tel`, `time`, `url`, `week`, `toggle`, `radio`, `checkbox`, `range`, `textarea`, `dropdown` types. New types can be added via `Custom Form Elements`. |
| resultPath | string | undefined | A [dot-prop-immutable](https://github.com/debitoor/dot-prop-immutable) compatible path to store the form field value. |
| displayName | string | undefined | Display text for the form field. |
| className | string | undefined | ClassName for the root form field element. |
| isHidden | function | undefined | Method to hide form field element in runtime. `(store) => boolean` |
| optional | boolean | undefined | Says if the form field is optional. |
| placeholder | string | undefined | Placeholder text for the form elements |
| helpText | string | undefined | Help text for a form element |
| helpTextOptions | object | undefined | See rc-tooltip [props](https://github.com/react-component/tooltip#props) |
| options | array | [] | Array of options. `({ value: any, label: any })[]` |
| separator | string | ',' | Separator to join/separate multiple values. Used by checkbox, multi-dropdown, etc. |
| topComponent | function | undefined | Method to render any additional elements to the top of the form field element. `(store) => JSX.Element` |
| simpleValues | boolean | false | Handle multi values as string. Works along with `separator`. |
| bottomComponent | function | undefined | Method to render any additional elements to the bottom of the form field element. `(store) => JSX.Element` |
| componentProps | object | undefined | Any additional props that should be passed to the underlying form field element. For example, to make the `dropdown` multi-select, pass `componentProps: { multiple: true }`. |
| instantValidation | boolean | false | Do validation on user input. |
| required | boolean | false | Make the field required. |
| validation | function | undefined | Method to perform validation. `(value) => errorMessage|null` |
| modifyStoreBeforeChange | function | undefined | Method to modify store before `onChange` handler is called. `(config, value, store) => store`. |### Available `componentProps`
#### `type: toggle`
| Property | Type | Default | Description |
| -------- | ------ | --------- | ----------------------------------------------------------- |
| infoText | string | undefined | Info text to be displayed to the right of the toggle switch |#### `type: range`
| Property | Type | Default | Description |
| --------- | ------- | ------- | --------------------------------------------- |
| showRange | boolean | true | Shows the `min` and `max` value of the slider |
| showValue | boolean | true | Shows the current range value explicitly |## Form Groups
It is possible to group form elements. Take a look at the following example.
```javascript
import 'formland/css/index.css'
import React, { Component } from 'react'
import Form from 'formland'class Example extends Component {
constructor() {
super()
this.state = {}
this.onChange = this.onChange.bind(this)
}onChange(newState) {
this.setState(newState)
}render() {
const config = [
{
id: 'group-1',
type: 'group',
displayName: 'Group 1',
description: 'This is group 1',
elements: [
{
id: 'firstName',
type: 'text',
displayName: 'First Name',
resultPath: 'name.firstName',
placeholder: 'Enter your first name',
},
{
id: 'LastName',
type: 'text',
displayName: 'Last Name',
resultPath: 'name.LastName',
placeholder: 'Enter your last name',
},
],
},
{
id: 'group-2',
type: 'group',
displayName: 'Group 2',
description: 'This is group 1',
elements: [
{
id: 'country',
type: 'text',
displayName: 'First Name',
resultPath: 'name.country',
placeholder: 'Enter your country',
},
{
id: 'state',
type: 'text',
displayName: 'Last Name',
resultPath: 'name.state',
placeholder: 'Enter your state',
},
],
},
]return
}
}
```## Validation
Validations are done per form element. Add a `validation()` method in the form element config. Validations can be done in two ways.
* Set `instantValidation: true` in the form element config. Now, the validation method will be called each time on user input.
* Use `validate()` method of the form instance. This returns an array of errors, if any. Useful for conditional based approach.
```javascript
import 'formland/css/index.css'
import React, { Component } from 'react'
import Form from 'formland'class Example extends Component {
constructor() {
super()
this.state = {}
this.onChange = this.onChange.bind(this)
}onChange(newState) {
this.setState(newState)
}onSubmit() {
const errors = this.form.validate()
console.log(errors)
}render() {
const config = [
{
id: 'answer',
type: 'text',
displayName: 'What is 4 + 5',
resultPath: 'answer',
placeholder: 'Answer',
validation: value => value !== '9' && 'Wrong Answer',
},
]return (
(this.form = el)}
config={config}
store={this.state}
onChange={this.onChange}
/>
)
}
}
```## Modify store value directly from config
You can access the store and change any store value directly from the config using `modifyStoreBeforeChange` method. This method will be called before `onChange` event. You can return a modified state and it will be passed to the `onChange` handler. The primary use case for this will be, to change a form value based on another form value.
```javascript
import 'formland/css/index.css'
import React, { Component } from 'react'
import Form from 'formland'class Example extends Component {
constructor() {
super()
this.state = {}
this.onChange = this.onChange.bind(this)
}onChange(newState) {
this.setState(newState)
}render() {
const config = [
{
id: 'firstName',
type: 'text',
displayName: 'First Name',
resultPath: 'name.firstName',
placeholder: 'Enter your first name',
modifyStoreBeforeChange: (config, value, store) => {
store.readonly = value
return store
},
},
{
id: 'readyonly',
type: 'text',
displayName: 'Output',
resultPath: 'readonly',
componentProps: {
disabled: true,
},
},
]return
}
}
```## Custom Buttons
It is possible to add custom buttons. Just wrap your buttons with ``.
```javascript
(this.form = el)}
config={config}
store={this.state}
onChange={this.onChange}
>
Custom Button```
## Custom Form Elements
Custom form elements can be added to any instance of formland via `customComponentResolvers` and `customValueResolvers` props.
* `customComponentResolvers(type: string) => ({ config: IReactFormConfig, value: any, callbacks: any }) => JSX.Element`
Returns a valid React stateless function based on the custom type.
* `customValueResolvers(config: IReactFormConfig, value: any) => any`
Returns a resolved value based on the custom type.
See the following example to understand how it works.
```javascript
import 'formland/css/index.css'
import React, { Component } from 'react'
import Select from 'react-select'
import Form, { getNewState } from 'formland'const customComponentsResolver = (type) => {
switch(type) {
case 'custom-dropdown':
return ({ config, value = '', callbacks= {}}) =>
default:
return
}
}const customValueResolver = (config: any, value: any) => {
switch (config.type) {
case 'react-select':
return value ? value.value : ''
}
}class Example extends Component {
constructor() {
super()
this.state = {}
this.onChange = this.onChange.bind(this)
}onChange(newState) {
this.setState(newState)
}render() {
const config = [
{
id: 'firstName',
type: 'custom-dropdown',
resultPath: 'country'
displayName: 'Shipping Country',
placeholder: 'Select a country',
options: [
{
value: 'india',
label: 'India',
},
{
value: 'usa',
label: 'The United States',
},
{
value: 'china',
label: 'China',
}
],
},
]return
}
}
```## Custom Form Element Packages
* [formland-react-select](https://github.com/praneshr/formland-react-select) - `react-select` components for formland
## Development
```bash
yarn install
yarn build
yarn start:examples
```Refer `package.json` for more commands
## License
MIT