@langleyfoxall/react-dynamic-form-builder
v1.2.0-rc.8
Published
A form builder for React that allows input filters, transformers and validators as well as custom input rendering
Downloads
149
Readme
Contents
Installation
form-builder
can be installed with NPM or Yarn.
# Installing with NPM
npm i --save @langleyfoxall/react-dynamic-form-builder
# Installing with Yarn
yarn add @langleyfoxall/react-dynamic-form-builder
Basic Example
Check out the demo.
// ./forms/create-user.js
export default [
{
name: 'first_name',
label: 'First Name'
},
{
name: 'last_name',
label: 'Last Name'
},
{
name: 'email_address',
label: 'Email Address',
type: 'email'
},
{
name: 'password',
label: 'Password',
type: 'password'
},
{
name: 'confirmation_password',
label: 'Confirm Password',
type: 'password'
},
];
// ./components/create-user-modal.jsx
import React from 'react';
import axios from 'axios';
import FormBuilder from '@langleyfoxall/react-dynamic-form-builder';
import Modal from './modal';
import Form from '../forms/create-user';
class CreateUserModal extends React.Component {
onSubmit(submission) {
return new Promise(resolve => (
axios
.post('/api/register', submission.data.form)
.then(() => console.log('Successfully signed up'))
.catch(() => console.log('Unable to sign up'))
.finally(resolve)
))
}
render() {
return (
<Modal>
<FormBuilder
form={Form}
onSubmit={this.onSubmit}
submitButton={{
text: 'Sign Up'
}}
/>
</Modal>
)
}
}
export default CreateUserModal;
Usage
form-builder
makes it easier to create dynamic react forms by handling most of the logic involved.
Props
The following props can be passed:
defaultInputClass
(string, default:input
)defaultLabelClass
(string, default:label
)defaultContainerClass
(string, default:container
)defaultValidationErrorClass
(string, default:error-label
)defaultSubmitClass
(string, defaultsubmit
)defaultValues
(object, default:{}
)values
(object, default:null
)classPrefix
(string, default:rdf
)invalidInputClass
(string, default:invalid
)validInputClass
(string, default:valid
)validationTimeout
(number, default:1000
)submitButton
(object,{ text, className? }
)onSubmit
(function)loading
(boolean, defaultfalse
)loadingElement
(element, defaultnull
)formErrors
(object, default:{}
)form
(array)
defaultInputClass
defaultInputClass
is appended to classPrefix
on inputs.
// With default value
'rdf-input'
defaultLabelClass
defaultLabelClass
is appended to classPrefix
on labels.
// With default value
'rdf-label'
defaultContainerClass
defaultContainerClass
is appended to classPrefix
on input containers.
// With default value
'rdf-container'
defaultValidationErrorClass
defaultValidationErrorClass
is appended to classPrefix
on error texts.
// With default value
'rdf-error-label'
defaultSubmitClass
defaultSubmitClass
is appended to classPrefix
on the managed submit button.
// With default value
'rdf-submit'
defaultValues
defaultValues
is used to pre-populate the inputs. It matches the property name against an input name.
// With default value
{}
// With custom value
{
first_name: 'John',
last_name: 'Doe',
}
values
values
is used to overwrite the state of the form and set values from outside the form.
This should be used in conjunction with onChange
.
// With default value
null
// With custom value
{
first_name: 'John',
last_name: 'Doe',
}
classPrefix
classPrefix
is used to prefix the majority of the class names.
// With default value
'rdf'
invalidInputClass
invalidInputClass
is appended to classPrefix
on invalid inputs.
// With default value
'rdf-invalid'
validInputClass
validInputClass
is appended to classPrefix
on valid inputs.
// With default value
'rdf-valid'
submitButton
submitButton
can be used to pass a managed submit button into the form.
className
is optional and gets appended to classPrefix
.
// With custom value
{
text: 'Sign up'
// className: 'secondary-button'
// > 'rdf-secondary-button'
}
onSubmit
onSubmit
should be called when the form is ready to be submitted, it is also triggered when the submitButton
is pressed.
When onSubmit
is triggered the callback will recieve an object containing:
{
valid, // Boolean for valid state of inputs
data: {
form, // Data from inputs
validation_errors // An object of errors for each input
}
}
loading
loading
is used to trigger a loading state on the form which is used to show the loading state
on the managed submit button when a loadingElement
has been passed.
// With default value
false
loadingElement
loadingElement
is shown when loading
is true
and a submitButton
has been passed.
// With default value
null
// With custom value
<p>Loading...</p>
formErrors
formErrors
is used to display extra errors that cannot be managed internally by the form builder.
// With default value
{}
// With custom value
{
first_name: '\'John\' is an invalid first name',
}
form
form
is used to pass the schema used to build the form. This will be explained in more detail here.
// With custom value
[
{
name: 'first_name',
},
]
Schema
A form schema can be passed into the form
prop. This is used to build the form and display the inputs correctly. The schema consists of an array and child elements. A child can be an array
or object
. If an array
is found then any objects
inside will be put on the same row as each other (or wrapped in the same parent container).
Each object
child needs at least a name
, but can also become more complex and custom:
name
(string)placeholder
(string)label
(string, function, string{})type
(string, defaultstring
)render
(function/node)options
(object[])radioContainerClass
(string)containerClass
(string)inputClass
(string)defaultValue
(mixed)defaultOptionText
(string)validationRules
(string, string[], object, object[], RegExp, RegExp[], function, function[])transformer
(function{})filter
(string, function, RegExp)autocomplete
(boolean)renderIf
(function)
name
name
is used for when data is submitted and passed back to the onSubmit
callback.
// With custom value
{
name: 'first_name',
}
placeholder
placeholder
is used to add placeholder text on empty text inputs.
// With custom value
{
name: 'first_name',
placeholder: 'Enter a first name',
}
label
label
is used to add a label above the input.
If an object is passed then at least text
is required. className
is optional.
// With custom value
{
name: 'fist_name',
label: 'First Name',
}
{
name: 'first_name',
label: {
text: 'First Name',
className: 'first-name-label'
}
}
{
name: 'first_name',
label: props => (
<label {...props}>
First Name
</label>
)
}
type
type
is used to change what type of input is rendered. Valid types input:
- text
- custom
- password
- date
- month
- number
- range
- color
- search
- time
- url
- week
- textarea
- checkbox
- select
- radio
// With default value
{
name: 'first_name',
type: 'string',
}
If custom
is passed then it is recommended that render
is also set.
render
render
is used when a normal input is not enough. This can be used to completely customize an input.
When using a function it recieves the following parameters:
input
(current input object)value
(current input value)onChange
(onChange handler)onBlur
(onBlur handler)errors
(current input errors)state
(form state)
When using a node it recieves the following props:
name
(current input name)placeholder
(current input placeholder)onChange
(onChange handler)onBlur
(onBlur handler)invalid
(invalid boolean)
// With custom value
{
name: 'first_name',
render: () => (
<h1>Custom Render</h1>
),
}
{
name: 'first_name',
render: <h1>Custom Render</h1>,
}
It works great with community addons, such as form-select
.
// With form select
{
name: 'custom',
label: 'custom',
render: (
<Select
options={[
{ label: 'a', value: 'a' },
{ label: 'b', value: 'b' },
]}
/>
),
}
{
name: 'custom',
label: 'custom',
render: ({ name, placeholder }, value, onChange) => (
<Select
name={name}
placeholder={placeholder}
value={value}
onChange={onChange}
options={[
{ label: 'a', value: 'a' },
{ label: 'b', value: 'b' },
]}
/>
),
}
options
options
are used for type
s select
or radio
.
It should be an array of objects containing: text
and value
.
{
name: 'gender',
type: 'select',
options: [
{ text: 'Male', value: 'male' },
{ text: 'Female', value: 'female' },
{ text: 'Other', value: 'other' },
],
}
radioContainerClass
radioContainerClass
is appended to classPrefix
on the container when type
is radio
.
// With default value
'rdf-'
conatinerClass
containerClass
is appended to classPrefix
on the container when type
is not radio
.
// With default value
'rdf-container'
inputClass
inputClass
is appended to classPrefix
on the input.
// With default value
'rdf-input'
defaultValue
defaultValue
is inserted as the default value when the input has text, if type
is checkbox
then a truthy/falsey should be passed.
// With custom value
{
name: 'first_name',
defaultValue: 'John',
}
defaultOptionText
defaultOptionText
is used to select a placeholder option for when type
is select
.
// With custom value
{
name: 'gender',
defaultOptionText: 'Select a gender...',
}
validationRules
validationRules
is used when wanting to validate the content of the input. Valid validation rules:
required
(not empty)email
(valid email)decimal
(numeric with optional decimal points)
// With custom value
{
name: 'first_name',
validationRules: 'required',
}
{
name: 'age',
validationRule: /^\d+$/,
}
{
name: 'age',
validationRule: '/^\d+$/',
}
{
name: 'color',
validationRule: this.isValidColor
}
{
name: 'email_address',
validationRules: [
'required', 'email',
],
}
Note: Validation rule types can also be mixed.
transformer
tranformer
is used to tranform the data before it gets validated/stored.
It should be an object with the keys which define functions:
onChange
onBlur
// With custom value
{
name: 'first_name',
transformer: {
onChange: this.uppercaseWords
}
}
filter
filter
is used can specific characters should never get stored as a value. It
can be a string, function or RegExp. The character will be ignored if false
is returned from the filter.
There are some pre-defined filters:
numeric
decimal
// With pre-defined filter
{
name: 'currency',
filter: 'decimal'
}
// With function
{
name: 'currency',
filter: event => event.target.value === 'a'
}
// With RegExp
{
name: 'currency',
filter: /[A-Ba-b]/
}
autocomplete
autocomplete
can be used in an attempt to counter user agent autofill. By setting
autocomplete
to false
a random input name is generated, rather than using the name
of the input object.
// With custom value
{
name: 'username',
autocomplete: false
}
renderIf
renderIf
can be used to render inputs based on the state of the form. When an input
is hidden from the form the validationErrors
and form value is reset.
// With custom value
{
name: 'last_name',
// Render if `first_name` has a truthy value
renderIf: ({ form }) => (
!!form.first_name
)
}
Addons
A list of community addons, designed to work flawlessly with form-builder
.
Make your own
Check out schema.render
on how to format your component to work well with form-builder
. When creating your component be mindful of what props are passed.
When using a function it recieves the following parameters:
input
(current input object)value
(current input value)onChange
(onChange handler)onBlur
(onBlur handler)errors
(current input errors)state
(form state)
When using a node it recieves the following props:
name
(current input name)placeholder
(current input placeholder)onChange
(onChange handler)onBlur
(onBlur handler)invalid
(invalid boolean)