@smashing/form
v0.7.3
Published
MobX powered forms in React
Downloads
17
Readme
Smashing Form
- ⚡ Fast input rerenders - doesn't rerender whole form
- 🥓 Well cooked api
- 👌 Form validation based on yup
- ⚖ It's lightweight
Examples
Install
npm install --save @smashing/form mobx mobx-react-lite
Usage
import * as React from 'react'
import {useForm} from '@smashing/form'
const CustomTextInput = props => <input type="text" {...props} />
export const MyForm = () => {
// Use `useForm` hook. `initialValues` is the only required value.
const {Form, Field, form} = useForm({
initialValues: {
email: '',
password: '',
},
onSubmit: values => console.log(values),
})
// Wrap your inputs with `Form` returned by `useForm`
return (
<Form>
{/* Each input should be wrapped in `Field` returned by `useForm` */}
<Field component={CustomTextInput} name="email" />
{/* "input" is default component used by field */}
<Field name="password" />
<button type="submit">Submit</button>
</Form>
)
}
Options
const {} = useForm({
initialValues,
validationSchema,
onSubmit,
validateOnBlur,
validateOnChange,
validateOnSubmit,
})
initialValues
- required
Object containing initial values of form. Can contain nested state.
validationSchema
- default: undefined
Read yup docs to learn more.
onSubmit
- default: undefined
Form submit handler
validateOnBlur
- default: false
Control if data should be validated on input blur
validateOnChange
- default: false
Control if data should be validated on input change
validateOnSubmit
- default: true
Control if data should be validated on form submit
Validation
You can use yup to validate form data.
import * as React from 'react'
import * as yup from 'yup'
import {useForm} from '@smashing/form'
const TextInput = props => <input type="text" {...props} />
const validationSchema = yup.object().shape({
email: yup
.string()
.email('Email is not valid.')
.max(64, 'Email is too long.')
.required('This field is required.'),
password: yup
.string()
.min(6, 'Password is too short.')
.max(64, 'Password is too long.')
.required('This field is required.'),
})
export const MyForm = () => {
const {Form, Field, form} = useForm({
initialValues: {
email: '',
password: '',
},
validationSchema,
onSubmit: values => console.log(values),
})
return (
<Form>
<Field component={TextInput} name="email" />
<Field component={TextInput} name="password" />
<button type="submit">Submit</button>
</Form>
)
}
Accessing form state
You can access whole state and form actions using form
property returned from useForm
.
const {form} = useForm({})
It contains the following state:
{
"isSubmitting": false,
"isValidating": false,
"isDirty": false,
"isValid": true,
"submitCount": 0,
"validateOnChange": false,
"validateOnBlur": false,
"validateOnSubmit": true,
"values": {},
"initialValues": {},
"errors": {},
"touched": {}
}
Accessing form state in nested components
You can access form state using context. FormContext
and useFormContext
are exported from package.
import {useFormContext, FormContext} from '@smashing/form'
const NestedComponent = () => {
const {form} = useFormContext()
// OR const {form} = React.useContext(FormContext)
}
FormContext
/useFormContext
can be used only insideForm
component returned fromuseForm
.
Handling nested data and arrays
const MyForm = () => {
const {Form, Field} = useForm({
initialValues: {
email: '',
social: {
twitter: '',
facebook: '',
},
friends: [{name: 'John'}, {name: 'Jane'}],
},
})
return (
<Form>
<Field component={TextInput} name="email" />
<Field component={TextInput} name="social.twitter" />
<Field component={TextInput} name="social.facebook" />
<Field component={TextInput} name="friends.0.name" />
<Field component={TextInput} name="friends.1.name" />
</Form>
)
}
Manipulating array items:
const {form} = useForm({
initialValues: {
friends: ['John', 'Jane'],
},
})
// Add new item
form.values.friends.push('')
// Remove first item
form.values.friends.splice(0, 1)
Form actions
You can operate on form state using form
object returned by useForm
:
const {form} = useForm({
initialValue: {
email: '',
password: '',
},
})
form.setFieldValue('email', '[email protected]')
reset: (nextState?: {values: {}, errors: {}, touched: {}}): void
Rest form values, errors and touch states to initial state:
form.reset()
Optionally nextState
object can be passed:
form.reset({
values: {email: '[email protected]'},
errors: {password: 'Password is required'},
touched: {
email: true,
password: true,
},
})
submit: (): void
Trigger onSubmit
handler.
validate: (field?: string): void
Validate all inputs:
form.validate()
Validate single input:
form.validate('email')
setIsSubmitting: (value: boolean): void
Start or finish submission process:
form.setIsSubmitting(true)
setValues: (values: Values): void
Set all input values:
form.setValues({
email: '',
password: '',
})
setErrors: (errors: FormErrors): void
Set all validation errors:
form.setErrors({
email: 'Email is invalid',
password: 'Password is to short',
})
setTouched: (values: FormTouched): void
Set all inputs touch state:
form.setTouched({
email: true,
password: false,
})
setFieldValue: (field: string, value: any): void
Set single field value:
form.setFieldValue('email', '[email protected]')
setFieldError: (field: string, message?: string): void
Set single field error message:
form.setFieldError('email', 'Email is invalid')
setFieldTouched: (field: string, isTouched: boolean): void
Set single field touch state:
form.setFieldTouched('email', true)
License
MIT © EYEDEA AS