dry-forms
v1.0.2
Published
React form validation
Downloads
3
Maintainers
Readme
Dry Forms
DryForms is a form validation library for React.
DryForms is a lightweight, leaner and easy-to-use alternative to Formik library that gives you more freedom in how to validate input values in a HTML form.
Though it is inspired by Formic, it takes a different, more functional approach to the process of verifying form field values.
Install
npm install -S dry-forms
yarn add dry-forms
Usage
Wrap your form into a function and pass that function into <Validate></Validate>
component.
Below is an example component that has a simple 'subscribe' form:
Example 1, basic validation
import React from "react"
import { Validate } from 'dry-forms'
const required = (s: string) => s.length>0
const isEmail = (s: string) => /^[\w.%+-]+@[\w-.]+\.[\w-]{2,}$/i.test(s)
const validators = {
name: required,
email: [required, isEmail]
}
const initials = {name: '', email: ''}
export default function Form1() {
return <Validate validators={validators} values={initials}>
{(values, errors, setVal, validate) => {
const submit = () => {
if (validate()) {
console.log('submit: ', values)
}
}
return <form noValidate onSubmit={e => {e.preventDefault(); submit()}}>
<input
placeholder="Your name"
value={values.name}
onChange={e => setVal('name', e.target.value)}
className={errors.includes('name') ? 'error' : ''}
/>
<input
placeholder="E-mail"
value={values.email}
onChange={e => setVal('email', e.target.value)}
className={errors.includes('email') ? 'error' : ''}
/>
<input
type='submit'
value="Submit"
/>
</form>
}}
</Validate>
}
Each field in the form can have a single validator or an array of validators assigned to it in the validators
array that you pass as a property to Validate
component.
Validator - is just a function! In its simplest form it takes a value and returns true
if the value is valid and false
otherwise.
When you set a new value for the field (by calling setVal function in the onChange
handler) DryForms calls every validator for that field starting from the first item in the array. If a validation function returns false, field's name is added to the errors
array and rest of validators are not called.Validate
component also takes values
property, that should have initial values for the form fields.
Example 2, messages
import React, { createRef } from "react"
import { Validators, required, isEmail, minLength, Validate } from 'dry-forms'
const notEmpty = required('Field is mandatory')
const validators: Validators = {
email: [notEmpty, isEmail('You entered invalid email address')],
password: [notEmpty, minLength(8, 'Use 8 or more characters')],
confirm: [
notEmpty,
(value: string, all, submitting) => {
if (!submitting) {
return true
}
const valid = value === all.password
return {valid, ...(!valid && {message: 'Passwords do not match'})}
}
]
}
const initials = {email: '', password: '', confirm: ''}
export default function Form2() {
const formRef = createRef<HTMLFormElement>()
return <Validate validators={validators} values={initials} form={formRef}>
{(values, errors, setVal, validate, messages) => {
const submit = () => {
if (validate()) {
console.log('submit: ', values)
}
}
return <form ref={formRef} noValidate onSubmit={e => {e.preventDefault(); submit()}}>
<input
name="email"
placeholder="E-mail"
value={values.email}
onChange={e => setVal('email', e.target.value)}
className={errors.includes('email') ? 'error' : ''}
/>
{'email' in messages && messages.email.map((m,i) => <span key={i}>{m}</span>)}
<input
type='password'
name="password"
placeholder="Password, use 8 or more characters"
value={values.password}
onChange={e => setVal('password', e.target.value)}
className={errors.includes('password') ? 'error' : ''}
/>
{'password' in messages && messages.password.map(m => <span key={m}>{m}</span>)}
<input
type='password'
name="confirm"
placeholder="Confirm password"
value={values.confirm}
onChange={e => setVal('confirm', e.target.value)}
className={errors.includes('confirm') ? 'error' : ''}
/>
{'confirm' in messages && messages.confirm.map(m => <span key={m}>{m}</span>)}
<input
type='submit'
value="Submit"
/>
</form>
}}
</Validate>
}
API Reference
Validate component
<Validate validators=... values=... form=...>
</Validate>
validators: Record<string, Validator|Validator[]>
type Validator = (value: any, all: Record<string, any>, sibmitting: boolean) => boolean|ValidationResult
interface ValidationResult {
valid: boolean
value?: any
message?: string
}
- value - a new value to validate
- all - read-only collection of all values
- sibmitting - whether it was called in the process of 'final' validation (e.g. in
onSubmit
handler), validate() sets this totrue
values: Record<string, any>
initial fields' values
form: React.RefObject< HTMLElement >
optional reference to the HTML form element. If passed, first input element with invalid value will receive focus after calling validate()
Validate child/render function
<Validate >
{
(values, errors, setVal, validate) => { /* ... */ }
}
</Validate>
values: Record<string, any>
Current field values.
errors: string[]
Array of failed field names.
setVal: (name: string, value: any, validate?: boolean = true, submitting?: boolean = false, focus?: boolean = false) => boolean
Function that sets the value for a field and optionally runs validation.
- name - field's name
- value - new field value
- validate -
true
to set a new value and validate it orfalse
to update a value without validation - submitting - if it was called in validate() presumably during submitting process
- focus -
true
to try to set focus on input element
validate: (dryRun?: boolean = false) => boolean
Validate all fields, returns true
if all values were sucessfully validated. The best place to call it in your onSubmit
handler, e.g.
onSubmit() {
if (validate()) {
// values are valid, it is OK to call fetch(...) etc.
}
}
- dryRun - do validation in a stealthy way, i.e. without adding errors and messages
...
<input
type='submit'
value="Submit"
disabled={!validate(true)} // <- check if valid but don't tell user about errors
/>