hoc-form
hoc-form copied to clipboard
Concise form validation for React! π
hoc-form β’

Tired of writing custom form validation on every project you might work on? Letβs try hocForm
, form validation on React has rarely been so simple! π€
Requirements
hocForm needs at least [email protected] and [email protected] to work.
Installation
Using npm
:
npm install --save hoc-form
yarn add hoc-form
works fine too!
Usage
import React from 'react';
import hocForm, { Field } from 'hoc-form';
// First, we need a input component to render our text field
function Input({
input = {},
label = '',
meta = {},
placeholder = '',
type = 'text',
}) {
return (
<div>
<label>
{label}
</label>
<input
placeholder={placeholder}
type={type}
{...input}
onBlur={e => input.onBlur && input.onBlur(e.target.value)}
onChange={e => input.onChange(e.target.value)}
/>
{meta.error && <span>{meta.error}</span>}
</div>
);
}
// Then, we need to create our form component and its helpers
const unavailableUsernames = [
'elonmusk',
'ironman',
'lukeskywalker',
];
function validateLogin(value = '') {
if (value.trim() === '') {
return Promise.reject('Please enter an username');
}
return unavailableUsernames.includes(value)
? Promise.reject('This username is unavailable')
: Promise.resolve()
}
function validatePassword(value = '') {
if (value.trim().length < 6) {
return Promise.reject('Password must contain 6 characters or more');
}
return Promise.resolve();
}
function Form({ onSubmit }) {
return (
<form onSubmit={onSubmit} noValidate>
<Field
name="login"
component={Input}
props={{
label: 'Login *',
onBlur: value => validateLogin(value),
placeholder: 'elonmusk',
type: 'string',
}}
/>
<Field
name="pwd"
component={Input}
props={{
label: 'Password *',
type: 'password',
}}
/>
<button type="submit">Sign up</button>
</form>
);
}
// Finally, an export of our wrapped form component
// with a validation function
export default hocForm({
validate(values, props) {
let errors = {};
const errorCatcher = (key, callback, ...args) => (
callback(values[key], args)
.catch(error => ({ [key]: error }))
);
return Promise.all([
errorCatcher('login', validateLogin),
errorCatcher('pwd', validatePassword),
]).then((errors) => {
const results = errors.reduce((acc, item) => ({ ...acc, ...item }), {});
return Object.keys(results).length ? Promise.reject(results) : Promise.resolve();
});
}
})(Form);
Please check out the complete demo! π
API
hocForm({ options })(MyFormComponent) => React.Component
Renders your MyFormComponent
contexted with hocForm
.
Two arguments are required:
- An
options
object to define thevalidate
function and optionalinitialValues
- A form
React.Component
to render.
options.validate(values, props) => Promise
Validates the form on submit.
Arguments:
-
values
(Object
): An object containing all fields keys and their value. -
props
(Object
): An object containing all props provided toMyFormComponent
.
Returns:
- A promise:
- On success, your must return
Promise.resolve()
- In case of failure, your must return
Promise.reject({})
. The object parameter must contain every field key with its error (type of string or else, depends on how your components used withField
are designed).
- On success, your must return
Example, with errors as strings:
function validate(values, props) {
let errors = {};
if (values.username) {
if (!props.isUsernameAvailable(values.username)) {
errors = { ...errors, username: 'This username is unavailable' };
}
} else {
errors = { ...errors, username: 'Please enter an username' };
}
if (!values.password) {
errors = { ...errors, password: 'Please enter a password' };
}
return Object.keys(errors).length
? Promise.reject(errors)
: Promise.resolve();
}
options.initialValues: Object
Object containing all initial values following fields keys.
Example:
initialValues: {
country: 'United Kingdom',
phone: '+44',
}
MyFormComponent: React.Component
A React.Component
rendering a form including some hocForm.Field
items.
Example:
function Form({ onSubmit }) {
return (
<form onSubmit={onSubmit} noValidate>
<Field
name="login"
component={Input}
props={{
label: 'Login *',
type: 'string',
}}
/>
/>
);
}
Please check out a complete example here.
Field({ options }) => React.Component
Renders a form field, contexted with hocForm
.
options.name: String
The name used in your options.validate
function.
Example:
<Field
name="login"
/>
options.component: React.Component
The React.Component
rendered by Field
.
Example:
<Field
component={Input}
/>
options.props: Object
The properties provided to the component
parameter.
Example:
<Field
props={{
label: 'Login *',
onBlur: (value, otherValues) => Promise.resolve(),
placeholder: 'elonmusk',
type: 'string',
}}
/>
Please check out a complete example here.
Which extra-props my components receive from Field
?
Components used in Field
must handle the two following properties: input
and meta
. Please check out the description below.
input.onChange(value: *)
Allows to dispatch the new value of the field to the hocForm
state. With this, all you have to do is to run input.onChange(theNewValue)
to allow hocForm
to use this new value at validation.
Example:
function TextInput({
input = {},
}) {
return (
<input
type="text"
onChange={e => input.onChange(e.target.value)}
/>
);
}
input.onBlur(value: *, values: Object) => Promise
Allows to run a validation on blur, the onBlur
callback setted as property of the Field
.
Example:
function TextInput({
input = {},
}) {
return (
<input
type="text"
onBlur={e => input.onBlur && input.onBlur(e.target.value)}
/>
);
}
Note:
When Field
runs the optional onBlur
callback received from its props
property, it runs this callback with two arguments:
-
value: *
, which is the current value of theField
; -
values: Object
, object containing all fields keys with their respective value. As example, this argument can be useful if you need to compare a Β« confirmation password Β» field with a previous Β« create password Β» field.
This callback must a return a Promise:
-
Promise.resolve()
if this blur validation succeeds; -
Promise.reject(error)
in case of failure.
Example:
<Field
name="confirmPwd"
component={Input}
props={{
label: 'Password confirmation *',
type: 'password',
onBlur: (currentValue, values) => (
currentValue.trim() !== values.firstPassword)
? Promise.reject('Please enter the same password as below')
: Promise.resolve()
),
}}
/>
options.meta: Object
Object containing about a potential error on the field.
Example:
function TextInput({
meta = {},
input = {},
}) {
return (
<React.Fragment>
<input
type="text"
onBlur={e => input.onBlur && input.onBlur(e.target.value)}
/>
{meta.error && <span>{meta.error}</span>}
</React.Fragment>
);
}
Please check out a complete example here.
License
hocForm is MIT licensed.