0.0.5 • Published 7 years ago

react-form-helper-sl v0.0.5

Weekly downloads
1
License
ISC
Repository
github
Last release
7 years ago

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.

Propdescriptiondefault
nameused as a key for storing value. This field is required and have to be unique
typeany input type eg: number, range, email, textarea, checkbox, radio, select ...text
defaultValueinitial field value""
defaultCheckedinitial field value for checkboxfalse
labelif provided, will render html <label>
optionsif 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' }]
classNamecss 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 replacedfield
validatecallback for validating input value. Can be function or array of functions. Function must return error string or undefined
componentThis 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 />
onChangecallback whenever input value changes. it gives tow parameters: event and validate(fieldName). validate can be used to trigger validation for another field
onBlurcallback 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.

Propdescription
isSubmittingtrue if form onSubmit is resolving promise
hasErrorstrue if any field has errors
componentThis 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, otherwise onSuccess 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-">&lt; 18</option>
			<option value="18-50">18-50</option>
			<option value="50+">&gt; 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