0.0.5 • Published 8 years ago
react-form-helper-sl v0.0.5
React form
A very simple and lightweight library to help build forms in React faster:
- manages form state by itself
- helps with field validation (client and server side)
- helps with async form submitting
import React from 'react';
import { Form, Field } from 'react-form-helper-sl';
const Form = () => (
<Form onSubmit={(values) => { /* { firstName: '', lastName: '' } */ }}>
<Field name="firstName" />
<Field name="lastName" />
<button type="submit">Submit</submit>
</Form>
);
export default Form;
Table of contents
Components
<Form />
This is for wrapping all form. It stores all form state. It also gives callbacks for onSubmit
, onSuccess
and onError
possible values
<Form
className="form"
onSubmit={(values) => { /* return promise, object with errors, true, false or nothing here */ }}
onSuccess={(reset) => { reset(); /* reset form values */ } }
onFail={(e) => { return e.validationErrors; /* return object where key is field name and value is error message */ } }
>
children
</Form>
<Field />
A single input. It can be any input or even custom component.
Prop | description | default |
---|---|---|
name | used as a key for storing value. This field is required and have to be unique | |
type | any input type eg: number , range , email , textarea , checkbox , radio , select ... | text |
defaultValue | initial field value | "" |
defaultChecked | initial field value for checkbox | false |
label | if provided, will render html <label> | |
options | if type is select , then you need to provide options as an array of objects, where object key is value and and object value is label. eg [{ value1: 'Value 1' }] | |
className | css class. If default renderer is used, it will generate following classNames: field , field--has-errors , field__input , field__error . If className is provided, field will be replaced | field |
validate | callback for validating input value. Can be function or array of functions. Function must return error string or undefined | |
component | This is used for rendering custom JSX instead default one. It gives two sets of parameters: input - required for making state updating to work, props - error, isTouched, className and any other custom parameter defined in <Field /> | |
onChange | callback whenever input value changes. it gives tow parameters: event and validate(fieldName) . validate can be used to trigger validation for another field | |
onBlur | callback whenever input is blurred. It gives one parameter: event |
possible values
<Field
name="requiredString"
type="number"
className="my-input"
defaultValue={7}
options={[{ option1: 'Option 1' }, { option1: 'Option 1' }]} // only used if type="select"
component={(input, props) => {}}
validate={(name, values) => values[name] < 1 && 'Has to be positive integer'}
transform={value => parseInt(value, 10)}
{...customProps}
/>
example
// If using custom component, it is possible to inject any property to component
const renderInput = (input, {label, error, isTouched}) => (
<div>
<label for={`input-${input.name}`}>{label}</label>
<input {...input} id={`input-${input.name}` />
{isTouched && error && (<span>{error}</span>)}
</div>
);
const Form = () => (
<Form onSubmit={(values) => { /* do something with values */ }}>
<Field name="firstName" label="First name" component={renderInput} />
<Field name="lastName" label="Last name" component={renderInput} />
<button type="submit">Submit</submit>
</Form>
);
<WithFormProp />
A way to render something conditionally based on current form state. It's basically a higher order component inside JSX.
Prop | description |
---|---|
isSubmitting | true if form onSubmit is resolving promise |
hasErrors | true if any field has errors |
component | This is used for rendering custom JSX instead default one. It gives a object with parameters: isSubmitting , hasErrors |
There are two ways to use it:
// renders only if isSubmitting is true.
<WithFormProp isSubmitting>
<p>Please wait</p>
</WithFormProp>
// Note that condition can also be negative. eg isSubmitting={false}
// use form props directly
<WithFormProp
component={({ hasErrors, isSubmitting }) => (
<button className="btn" type="submit" disabled={isSubmitting || hasErrors}>Send</button>
)}
/>
// possible values
<WithFormProp isSubmitting hasErrors={false} component={(values) => {}}>
children
</WithFormProp>
How validation works
- if field has been touched (input has been blurred at least once or user has tried to submit form), every time value is changed, it will validate itself.
- whenever form is submitted, all validations are run, and if no errors are found,
onSubmit
will be called - if
onSubmit
returns false,onError
is called. If promise is returned, it will resolve it, otherwiseonSuccess
is called
Examples
Full example can be found here
Custom Field renderer
// ...
const renderSelect = (input, { error, isTouched, className }) => (
<div className={className}>
<select {...input} className={`${className}__input`}>
<option value="18-">< 18</option>
<option value="18-50">18-50</option>
<option value="50+">> 50</option>
</select>
{isTouched && error && (
<span className={`${className}__error`}>{error}</span>
)}
</div>
);
const Form = () => (
<Form onSubmit={(values) => { /* do something with values */ }}>
<Field name="age" component={renderSelect} defaultValue="18-" />
<button type="submit">Submit</submit>
</Form>
);
// ...
Form validation
First name has to be defined. Last name have to be at least 5 characters long. IF checkbox is checked, email must be defined.
// ...
export const required = (name, values) => (values[name] ? undefined : 'Field is required');
const minLength = min => (name, values) =>
(values[name] && values[name].length < min ? `Must be at least ${min} characters` : undefined);
const requiredIfHasField = fieldName => (name, values) =>
(values[fieldName] && !values[name] ? 'Field is required' : undefined);
const Form = () => (
<Form onSubmit={(values) => { /* do something with values */ }}>
<Field name="firstName" validate={required} />
<Field name="lastName" validate={[required, minLength(5)]} />
<Field type="email" name="email" validate={requiredIfHasField('subscribeToEmail')} />
<Field type="checkbox" name="subscribeToEmail" onChange={(e, validate) => { validate('email'); }} />
<button type="submit">Submit</submit>
</Form>
);
// ...
RUNNING EXAMPLES
- download project:
- run
npm install
- run
npm start
- open browser at localhost:3000
TODO
- travis integration
- tests
- improve documentation
- better bundle files