UNPKG

47.5 kBMarkdownView Raw
1![](https://user-images.githubusercontent.com/4060187/27243721-3b5219d0-52b1-11e7-96f1-dae8391a3ef6.png)
2
3[![gzip size](http://img.badgesize.io/https://unpkg.com/formik/dist/formik.umd.min.js?compression=gzip)](https://unpkg.com/formik/dist/formik.umd.min.js)
4[![Build Status](https://travis-ci.org/jaredpalmer/formik.svg?branch=master)](https://travis-ci.org/jaredpalmer/formik)
5[![npm](https://img.shields.io/npm/v/formik.svg)](https://npm.im/formik)
6[![license](http://img.shields.io/npm/l/formik.svg)](./LICENSE)
7[![Join the chat at on Slack](https://palmer.chat/badge.svg)](https://palmer.chat/)
8
9## Overview
10
11Let's face it, forms are really verbose in [React](https://github.com/facebook/react). To make matters worse, most form helpers do wayyyy too much magic and often have a significant performance cost associated with them. Formik is a small library that helps you with the 3 most annoying parts:
12
13 1. Getting values in and out of form state
14 2. Validation and error messages
15 3. Handling form submission
16
17By colocating all of the above in one place, Formik will keep things organized--making testing, refactoring, and reasoning about your forms a breeze.
18
19## Developer Experience
20
21I wrote Formik while building a large internal administrative dashboard with [Ian White](https://github.com/eonwhite). With around ~30 unique forms, it quickly became obvious that we could benefit by standardizing not just our input components but also the way in which data flowed through our forms.
22
23### Why not Redux-Form?
24
25By now, you might be thinking, "Why didn't you just use [Redux-Form](https://github.com/erikras/redux-form)?" Good question.
26
27 1. According to our prophet Dan Abramov, [**form state is inherently emphemeral and local**, so tracking it in Redux (or any kind of Flux library) is unnecessary](https://github.com/reactjs/redux/issues/1287#issuecomment-175351978)
28 2. Redux-Form calls your entire top-level Redux reducer multiple times ON EVERY SINGLE KEYSTROKE. This is fine for small apps, but as your Redux app grows, input latency will continue increase if you use Redux-Form.
29 3. Redux-Form is 22.5 kB minified gzipped (Formik is 9.2 kB)
30
31**My goal with Formik was to create a scalable, performant, form helper with a minimal API that does the really really annoying stuff, and leaves the rest up to you.**
32
33## Influences
34
35Formik started by expanding on [this little higher order component](https://github.com/jxnblk/rebass-recomposed/blob/master/src/withForm.js) by [Brent Jackson](https://github.com/jxnblk), some naming conventions from Redux-Form, and (most recently) the render props approach popularized by [React-Motion](https://github.com/chenglou/react-motion) and [React-Router 4](https://github.com/ReactTraining/react-router). Whether you have used any of the above or not, Formik only takes a few minutes to get started with.
36
37## Installation
38
39Add Formik to your project.
40
41```bash
42npm i formik --save
43```
44
45You can also try before you buy with this **[demo of Formik on CodeSandbox.io](https://codesandbox.io/s/zKrK5YLDZ)**
46
47## Demos
48
49- [Basics](https://codesandbox.io/s/zKrK5YLDZ)
50- [Sync Validation](https://codesandbox.io/s/q8yRqQMp)
51- [Building your own input primitives](https://codesandbox.io/s/qJR4ykJk)
52- [Working with 3rd-party inputs #1: react-select](https://codesandbox.io/s/jRzE53pqR)
53- [Working with 3rd-party inputs #2: Draft.js](https://codesandbox.io/s/QW1rqjBLl)
54- [Accessing React lifecycle functions](https://codesandbox.io/s/pgD4DLypy)
55
56## Talks
57
58- [An Introduction to Formik](https://youtu.be/-tDy7ds0dag?t=33s) by [Jared Palmer](https://twitter.com/jaredpalmer) @ Spotify NYC. August 15th, 2017.
59
60## The gist
61
62Formik keeps track of your form's state and then exposes it plus a few reusable methods and event handlers (`handleChange`, `handleBlur`, and `handleSubmit`) to your form via `props`. `handleChange` and `handleBlur` work exactly as expected--they use a `name` or `id` attribute to figure out which field to update.
63
64There are two ways to use Formik:
65
66- `withFormik()`: A Higher-order Component (HoC) that accepts a configuration object
67- `<Formik />`: A React component with a `render` prop
68
69**Both do exactly the same thing** and share the same internal implementation. They just differ in their respective style....
70
71```js
72// Higher Order Component
73import React from 'react'
74import { withFormik } from 'formik'
75
76// Our inner form component which receives our form's state and updater methods as props
77const InnerForm = ({ values, errors, touched, handleChange, handleSubmit, isSubmitting }) =>
78 <form onSubmit={handleSubmit}>
79 <input
80 type="email"
81 name="email"
82 onChange={handleChange}
83 value={values.email}
84 />
85 {touched.email && errors.email && <div>{errors.email}</div>}
86 <input
87 type="password"
88 name="password"
89 onChange={handleChange}
90 value={values.password}
91 />
92 {touched.password && errors.password && <div>{errors.password}</div>}
93 <button type="submit" disabled={isSubmitting}>Submit</button>
94 </form>
95
96// Wrap our form with the using withFormik HoC
97const MyForm = withFormik({
98 // Transform outer props into form values
99 mapPropsToValues: props => ({ email: '', password: '' }),
100 // Add a custom validation function (this can be async too!)
101 validate: (values, props) => {
102 let errors = {}
103 if (!values.email) {
104 errors.email = 'Required'
105 } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
106 errors.email = 'Invalid email address'
107 }
108 return errors
109 },
110 // Submission handler
111 handleSubmit: (values, { props, setSubmitting, setErrors, /* setValues, setStatus, and other goodies */ }) => {
112 LoginToMyApp(values)
113 .then(
114 user => {
115 setSubmitting(false)
116 // do whatevs...
117 // props.updateUser(user)
118 },
119 errors => {
120 setSubmitting(false)
121 // Maybe even transform your API's errors into the same shape as Formik's!
122 setErrors(transformMyApiErrors(errors))
123 }
124 )
125 }
126})(InnerForm)
127
128// Use <MyForm /> anywhere
129const Basic = () =>
130 <div>
131 <h1>My Form</h1>
132 <p>This can be anywhere in your application</p>
133 <MyForm />
134 </div>
135
136export default Basic
137```
138
139```js
140// Render Prop
141import React from 'react'
142import { Formik } from 'formik'
143
144const Basic = () =>
145 <div>
146 <h1>My Form</h1>
147 <p>This can be anywhere in your application</p>
148 {/*
149 The benefit of the render prop approach is that you have full access to React's
150 state, props, and composition model. Thus there is no need to map outer props
151 to values...you can just set the initial values, and if they depend on props / state
152 then--boom--you can directly access to props / state.
153
154 The render prop accepts your inner form component, which you can define separately or inline
155 totally up to you:
156 - `<Formik render={props => <form>...</form>}>`
157 - `<Formik component={InnerForm}>`
158 - `<Formik>{props => <form>...</form>}</Formik>` (identical to as render, just written differently)
159 */}
160 <Formik
161 initialValues={{
162 email: '',
163 password: ''
164 }}
165 validate={values => {
166 // same as above, but feel free to move this into a class method now.
167 let errors = {}
168 if (!values.email) {
169 errors.email = 'Required'
170 } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
171 errors.email = 'Invalid email address'
172 }
173 return errors
174 }}
175 onSubmit={(values, { setSubmitting, setErrors, /* setValues and other goodies */ }) => {
176 LoginToMyApp(values)
177 .then(
178 user => {
179 setSubmitting(false)
180 // do whatevs...
181 // props.updateUser(user)
182 },
183 errors => {
184 setSubmitting(false)
185 // Maybe transform your API's errors into the same shape as Formik's
186 setErrors(transformMyApiErrors(errors))
187 }
188 )
189 }}
190 render={({ values, errors, touched, handleChange, handleSubmit, isSubmitting }) =>
191 <form onSubmit={handleSubmit}>
192 <input
193 type="email"
194 name="email"
195 onChange={handleChange}
196 value={values.email}
197 />
198 {touched.email && errors.email && <div>{errors.email}</div>}
199 <input
200 type="password"
201 name="password"
202 onChange={handleChange}
203 value={values.password}
204 />
205 {touched.password && errors.password && <div>{errors.password}</div>}
206 <button type="submit" disabled={isSubmitting}>Submit</button>
207 </form>}
208 />
209 </div>
210
211export default Basic
212```
213
214### Complementary Packages
215
216As you can see above, validation is left up to you. Feel free to write your own validators or use a 3rd party library. Personally, I use [Yup](https://github.com/jquense/yup) for object schema validation. It has an API that's pretty similar [Joi](https://github.com/hapijs/joi) / [React PropTypes](https://github.com/facebook/prop-types) but is small enough for the browser and fast enough for runtime usage. Because I :heart: Yup sooo much, Formik has a special config option / prop for Yup called [`validationSchema`] which will automatically transform Yup's validation errors into a pretty object whose keys match [`values`] and [`touched`]. Anyways, you can install Yup from npm...
217
218```
219npm install yup --save
220```
221
222
223<!-- START doctoc generated TOC please keep comment here to allow auto update -->
224<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
225**Table of Contents**
226
227- [Usage](#usage)
228 - [Simple Example](#simple-example)
229- [API](#api)
230 - [`<Formik />`](#formik-)
231 - [Formik render methods](#formik-render-methods)
232 - [Formik props](#formik-props)
233 - [`dirty: boolean`](#dirty-boolean)
234 - [`errors: { [field: string]: string }`](#errors--field-string-string-)
235 - [`handleBlur: (e: any) => void`](#handleblur-e-any--void)
236 - [`handleChange: (e: React.ChangeEvent<any>) => void`](#handlechange-e-reactchangeeventany--void)
237 - [`handleReset: () => void`](#handlereset---void)
238 - [`handleSubmit: (e: React.FormEvent<HTMLFormEvent>) => void`](#handlesubmit-e-reactformeventhtmlformevent--void)
239 - [`isSubmitting: boolean`](#issubmitting-boolean)
240 - [`isValid: boolean`](#isvalid-boolean)
241 - [`resetForm: (nextValues?: Values) => void`](#resetform-nextvalues-values--void)
242 - [`setErrors: (fields: { [field: string]: string }) => void`](#seterrors-fields--field-string-string---void)
243 - [`setFieldError: (field: string, errorMsg: string) => void`](#setfielderror-field-string-errormsg-string--void)
244 - [`setFieldTouched: (field: string, isTouched: boolean) => void`](#setfieldtouched-field-string-istouched-boolean--void)
245 - [`setFieldValue: (field: string, value: any) => void`](#setfieldvalue-field-string-value-any--void)
246 - [`setStatus: (status?: any) => void`](#setstatus-status-any--void)
247 - [`setSubmitting: (boolean) => void`](#setsubmitting-boolean--void)
248 - [`setTouched: (fields: { [field: string]: boolean }) => void`](#settouched-fields--field-string-boolean---void)
249 - [`setValues: (fields: { [field: string]: any }) => void`](#setvalues-fields--field-string-any---void)
250 - [`status?: any`](#status-any)
251 - [`touched: { [field: string]: boolean }`](#touched--field-string-boolean-)
252 - [`values: { [field: string]: any }`](#values--field-string-any-)
253 - [`component`](#component)
254 - [`render: (props: FormikProps<Values>) => ReactNode`](#render-props-formikpropsvalues--reactnode)
255 - [`children: func`](#children-func)
256 - [`enableReinitialize?: boolean`](#enablereinitialize-boolean)
257 - [`isInitialValid?: boolean`](#isinitialvalid-boolean)
258 - [`initialValues?: Values`](#initialvalues-values)
259 - [`onSubmit: (values: Values, formikBag: FormikBag) => void`](#onsubmit-values-values-formikbag-formikbag--void)
260 - [`validate?: (values: Values) => FormikError<Values> | Promise<any>`](#validate-values-values--formikerrorvalues--promiseany)
261 - [`validateOnBlur?: boolean`](#validateonblur-boolean)
262 - [`validateOnChange?: boolean`](#validateonchange-boolean)
263 - [`validationSchema?: Schema | (() => Schema)`](#validationschema-schema----schema)
264 - [`<Field />`](#field-)
265 - [`<Form />`](#form-)
266 - [`withFormik(options)`](#withformikoptions)
267 - [`options`](#options)
268 - [`displayName?: string`](#displayname-string)
269 - [`enableReinitialize?: boolean`](#enablereinitialize-boolean-1)
270 - [`handleSubmit: (values: Values, formikBag: FormikBag) => void`](#handlesubmit-values-values-formikbag-formikbag--void)
271 - [The "FormikBag":](#the-formikbag)
272 - [`isInitialValid?: boolean | (props: Props) => boolean`](#isinitialvalid-boolean--props-props--boolean)
273 - [`mapPropsToValues?: (props: Props) => Values`](#mappropstovalues-props-props--values)
274 - [`validate?: (values: Values, props: Props) => FormikError<Values> | Promise<any>`](#validate-values-values-props-props--formikerrorvalues--promiseany)
275 - [`validateOnBlur?: boolean`](#validateonblur-boolean-1)
276 - [`validateOnChange?: boolean`](#validateonchange-boolean-1)
277 - [`validationSchema?: Schema | ((props: Props) => Schema)`](#validationschema-schema--props-props--schema)
278 - [Injected props and methods](#injected-props-and-methods)
279- [Guides](#guides)
280 - [React Native](#react-native)
281 - [Why use `setFieldValue` instead of `handleChange`?](#why-use-setfieldvalue-instead-of-handlechange)
282 - [Avoiding a Render Callback](#avoiding-a-render-callback)
283- [Organizations and projects using Formik](#organizations-and-projects-using-formik)
284- [Authors](#authors)
285- [Contributors](#contributors)
286
287<!-- END doctoc generated TOC please keep comment here to allow auto update -->
288
289## Usage
290
291### Simple Example
292
293Imagine you want to build a form that lets you edit user data. However, your user API has nested objects like so.
294
295```js
296{
297 id: string,
298 email: string,
299 social: {
300 facebook: string,
301 twitter: string,
302 // ...
303 }
304}
305```
306
307When we are done we want our dialog to accept just a `user`, `updateUser`, and `onClose` props.
308
309```js
310// User.js
311import React from 'react';
312import Dialog from 'MySuperDialog';
313import EditUserForm from './EditUserForm';
314import { Formik } from 'formik'
315
316const EditUserDialog = ({ user, updateUser, onClose }) => {
317 const { email, social } = user
318 return (
319 <Dialog onClose={onClose}>
320 <h1>Edit User</h1>
321 <Formik
322 initialValues={{ email, ...social }}
323 onSubmit={(values, actions) => {
324 CallMyApi(user.id, values)
325 .then(
326 updatedUser => {
327 actions.setSubmitting(false)
328 updateUser(updatedUser),
329 onClose()
330 },
331 error => {
332 actions.setSubmitting(false)
333 actions.setErrors(transformMyAPIErrorToAnObject(error));
334 }
335 )
336 }}
337 render={({ values, errors, touched, handleBlur, handleChange, handleSubmit, isSubmitting }) =>
338 <form onSubmit={handleSubmit}>
339 <input
340 type="email"
341 name="email"
342 onChange={handleChange}
343 value={values.email}
344 />
345 {errors.email &&
346 touched.email &&
347 <div>
348 {errors.email}
349 </div>}
350 <input
351 type="text"
352 name="facebook"
353 onChange={handleChange}
354 value={values.facebook}
355 />
356 {errors.facebook &&
357 touched.facebook &&
358 <div>
359 {errors.facebook}
360 </div>}
361 <input
362 type="text"
363 name="twitter"
364 onChange={handleChange}
365 value={values.twitter}
366 />
367 {errors.twitter &&
368 touched.twitter &&
369 <div>
370 {errors.twitter}
371 </div>}
372 <button type="submit" disabled={isSubmitting}>
373 Submit
374 </button>
375 </form>}
376 />
377 </Dialog>
378 )
379}
380```
381
382To make writing forms less verbose. Formik comes with a few helpers to save you key strokes.
383
384- `<Field>`
385- `<Form/>`
386
387
388This is the **exact** same form as before, but written with `<Form/>` and `<Field/>`:
389
390```js
391// EditUserDialog.js
392import React from 'react';
393import Dialog from 'MySuperDialog';
394import EditUserForm from './EditUserForm';
395import { Formik, Field, Form } from 'formik'
396
397const EditUserDialog = ({ user, updateUser, onClose }) => {
398 const { email, social } = user
399 return (
400 <Dialog onClose={onClose}>
401 <h1>Edit User</h1>
402 <Formik
403 initialValues={{ email, ...social }}
404 onSubmit={(values, actions) => {
405 CallMyApi(user.id, values)
406 .then(
407 updatedUser => {
408 actions.setSubmitting(false)
409 updateUser(updatedUser),
410 onClose()
411 },
412 error => {
413 actions.setSubmitting(false)
414 actions.setErrors(transformMyAPIErrorToAnObject(error));
415 }
416 )
417 }}
418 render={({ errors, touched, isSubmitting }) =>
419 <Form>
420 <Field type="email" name="email" />
421 {errors.email &&
422 touched.email &&
423 <div>
424 {errors.email}
425 </div>}
426 <Field type="text" name="facebook" />
427 {errors.facebook &&
428 touched.facebook &&
429 <div>
430 {errors.facebook}
431 </div>}
432 <Field type="text" name="twitter" />
433 {errors.twitter &&
434 touched.twitter &&
435 <div>
436 {errors.twitter}
437 </div>}
438 <button type="submit" disabled={isSubmitting}>
439 Submit
440 </button>
441 </Form>}
442 />
443 </Dialog>
444 )
445}
446```
447
448## API
449
450### `<Formik />`
451
452`<Formik>` is a component that helps you with building forms. In uses a render props pattern made popular by libraries like React Motion and React Router.
453
454```js
455import React from 'react'
456import { Formik } from 'formik'
457
458const BasicExample = () =>
459 <div>
460 <h1>My Form</h1>
461 <Formik
462 initialValues={{ name: 'jared' }}
463 onSubmit={(values, actions) => {
464 setTimeout(() => {
465 alert(JSON.stringify(values, null, 2))
466 actions.setSubmitting(false)
467 }, 1000);
468 }}
469 render={(props) =>
470 <form onSubmit={props.handleSubmit}>
471 <input
472 type="text"
473 onChange={props.handleChange}
474 onBlur={props.handleBlur}
475 value={props.values.name}
476 name="name"
477 />
478 {props.errors.name &&
479 <div id="feedback">
480 {props.errors.name}
481 </div>}
482 <button type="submit">Submit</button>
483 </form>}
484 />
485 </div>;
486```
487
488#### Formik render methods
489
490There are three ways to render things with `<Formik/>`
491
492- `<Formik component>`
493- `<Formik render>`
494- `<Formik children>`
495
496#### Formik props
497
498All three render methods will be passed the same props:
499
500##### `dirty: boolean`
501
502Returns `true` if any field has been touched by any means, `false` otherwise. `dirty` is a readonly computed property and should not be mutated directly.
503
504##### `errors: { [field: string]: string }`
505
506Form validation errors. Should match the shape of your form's [`values`] defined in `initialValues`. If you are using [`validationSchema`] (which you should be), keys and shape will match your schema exactly. Internally, Formik transforms raw [Yup validation errors](https://github.com/jquense/yup#validationerrorerrors-string--arraystring-value-any-path-string) on your behalf. If you are using [`validate`], then that function will determine the `errors` objects shape.
507
508##### `handleBlur: (e: any) => void`
509`onBlur` event handler. Useful for when you need to track whether an input has been [`touched`] or not. This should be passed to `<input onBlur={handleBlur} ... />`
510
511DOM-only. Use [`setFieldTouched`] in React Native.
512
513##### `handleChange: (e: React.ChangeEvent<any>) => void`
514General input change event handler. This will update the `values[key]` where `key` is the event-emitting input's `name` attribute. If the `name` attribute is not present, `handleChange` will look for an input's `id` attribute. Note: "input" here means all HTML inputs.
515
516DOM-only. Use [`setFieldValue`] in React Native.
517
518##### `handleReset: () => void`
519Reset handler. Will reset the form to its initial state. This should be passed to `<button onClick={handleReset}>...</button>`
520
521##### `handleSubmit: (e: React.FormEvent<HTMLFormEvent>) => void`
522Submit handler. This should be passed to `<form onSubmit={props.handleSubmit}>...</form>`
523
524##### `isSubmitting: boolean`
525Submitting state. Either `true` or `false`. Formik will set this to `true` on your behalf before calling [`handleSubmit`] to reduce boilerplate.
526
527##### `isValid: boolean`
528
529Returns `true` if the there are no [`errors`], or the result of [`isInitialValid`] the form if is in "pristine" condition (i.e. not [`dirty`])).
530
531##### `resetForm: (nextValues?: Values) => void`
532Imperatively reset the form. This will clear [`errors`] and [`touched`], set [`isSubmitting`] to `false` and rerun `mapPropsToValues` with the current `WrappedComponent`'s `props` or what's passed as an argument. That latter is useful for calling `resetForm` within `componentWillReceiveProps`.
533
534##### `setErrors: (fields: { [field: string]: string }) => void`
535Set `errors` imperatively.
536
537##### `setFieldError: (field: string, errorMsg: string) => void`
538Set the error message of a field imperatively. `field` should match the key of [`errors`] you wish to update. Useful for creating custom input error handlers.
539
540##### `setFieldTouched: (field: string, isTouched: boolean) => void`
541Set the touched state of a field imperatively. `field` should match the key of [`touched`] you wish to update. Useful for creating custom input blur handlers.
542
543##### `setFieldValue: (field: string, value: any) => void`
544Set the value of a field imperatively. `field` should match the key of [`values`] you wish to update. Useful for creating custom input change handlers.
545
546##### `setStatus: (status?: any) => void`
547Set a top-level [`status`] to anything you want imperatively. Useful for controlling arbitrary top-level state related to your form. For example, you can use it to pass API responses back into your component in [`handleSubmit`].
548
549##### `setSubmitting: (boolean) => void`
550Set [`isSubmitting`] imperatively.
551
552##### `setTouched: (fields: { [field: string]: boolean }) => void`
553Set [`touched`] imperatively.
554
555##### `setValues: (fields: { [field: string]: any }) => void`
556Set [`values`] imperatively.
557
558##### `status?: any`
559A top-level status object that you can use to represent form state that can't otherwised be expressed/stored with other methods. This is useful for capturing and passing through API responses to your inner component.
560
561`status` should only be modifed by calling [`setStatus: (status?: any) => void`](#setstatus-status-any--void)
562
563##### `touched: { [field: string]: boolean }`
564Touched fields. Each key corresponds to a field that has been touched/visited.
565
566##### `values: { [field: string]: any }`
567Your form's values. Will have the shape of the result of [`mapPropsToValues`] (if specified) or all props that are not functions passed to your wrapped component.
568
569
570#### `component`
571
572```tsx
573<Formik component={ContactForm} />
574
575const ContactForm = ({ handleSubmit, handleChange, handleBlur, values, errors }) => {
576 return
577 <form onSubmit={handleSubmit}>
578 <input
579 type="text"
580 onChange={handleChange}
581 onBlur={handleBlur}
582 value={values.name}
583 name="name"
584 />
585 {errors.name &&
586 <div>
587 {errors.name}
588 </div>}
589 <button type="submit">Submit</button>
590 </form>
591}
592```
593**Warning:** `<Formik component>` takes precendence over `<Formik render>` so don’t use both in the same `<Formik>`.
594
595#### `render: (props: FormikProps<Values>) => ReactNode`
596
597```tsx
598<Formik render={props => <ContactForm {...props} />}/>
599
600<Formik
601 render={({ handleSubmit, handleChange, handleBlur, values, errors }) => (
602 <form onSubmit={handleSubmit}>
603 <input
604 type="text"
605 onChange={handleChange}
606 onBlur={handleBlur}
607 value={values.name}
608 name="name"
609 />
610 {errors.name &&
611 <div>
612 {errors.name}
613 </div>}
614 <button type="submit">Submit</button>
615 </form>
616 )}
617/>
618```
619
620#### `children: func`
621
622```tsx
623<Formik children={props => <ContactForm {...props} />}/>
624
625// or...
626
627<Formik>
628 {({ handleSubmit, handleChange, handleBlur, values, errors }) => (
629 <form onSubmit={handleSubmit}>
630 <input
631 type="text"
632 onChange={handleChange}
633 onBlur={handleBlur}
634 value={values.name}
635 name="name"
636 />
637 {errors.name &&
638 <div>
639 {errors.name}
640 </div>}
641 <button type="submit">Submit</button>
642 </form>
643 )}
644</Formik>
645```
646
647
648#### `enableReinitialize?: boolean`
649
650Default is `false`. Control whether Formik should reset the form if [`initialValues`] changes (using deep equality).
651
652#### `isInitialValid?: boolean`
653
654Default is `false`. Control the initial value of [`isValid`] prop prior to mount. You can also pass a function. Useful for situations when you want to enable/disable a submit and reset buttons on initial mount.
655
656#### `initialValues?: Values`
657
658Initial field values of the form, Formik will make these values available to render methods component as [`props.values`][`values`].
659
660Even if your form is empty by default, you must initialize all fields with initial values otherwise React will throw an error saying that you have changed an input from uncontrolled to controlled.
661
662Note: `initialValues` not available to the higher-order component, use [`mapPropsToValues`] instead.
663
664#### `onSubmit: (values: Values, formikBag: FormikBag) => void`
665Your form submission handler. It is passed your forms [`values`] and the "FormikBag", which includes an object containing a subset of the [injected props and methods](/#injected-props-and-methods) (i.e. all the methods with names that start with `set<Thing>` + `resetForm`) and any props that were passed to the the wrapped component.
666
667Note: [`errors`], [`touched`], [`status`] and all event handlers are NOT included in the `FormikBag`.
668
669#### `validate?: (values: Values) => FormikError<Values> | Promise<any>`
670
671_Note: I suggest using [`validationSchema`] and Yup for validation. However, `validate` is a dependency-free, straightforward way to validate your forms._
672
673Validate the form's [`values`] with function. This function can either be:
674
6751. Synchronous and return an [`errors`] object.
676
677```js
678// Synchronous validation
679const validate = (values, props) => {
680 let errors = {}
681
682 if (!values.email) {
683 errors.email = 'Required'
684 } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
685 errors.email = 'Invalid email address'
686 }
687
688 //...
689
690 return errors
691}
692```
693- Asynchronous and return a Promise that's error is an [`errors`] object
694
695```js
696// Async Validation
697const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
698
699const validate = (values, props) => {
700 return sleep(2000).then(() => {
701 let errors = {}
702 if (['admin', 'null', 'god']).includes(values.username) {
703 errors.username = 'Nice try'
704 }
705 // ...
706 if (Object.keys(errors).length) {
707 throw errors
708 }
709 })
710}
711```
712
713#### `validateOnBlur?: boolean`
714
715Default is `true`. Use this option to run validations on `blur` events. More specifically, when either [`handleBlur`], [`setFieldTouched`], or [`setTouched`] are called.
716
717#### `validateOnChange?: boolean`
718
719Default is `true`. Use this option to tell Formik to run validations on `change` events and `change`-related methods. More specifically, when either [`handleChange`], [`setFieldValue`], or [`setValues`] are called.
720
721#### `validationSchema?: Schema | (() => Schema)`
722
723[A Yup schema](https://github.com/jquense/yup) or a function that returns a Yup schema. This is used for validation. Errors are mapped by key to the inner component's [`errors`]. Its keys should match those of [`values`].
724
725### `<Field />`
726
727`<Field />` will automagically hook up inputs to Formik. It uses the `name` attribute to match up with Formik state. `<Field/>` will default to and `<input/>` element. To change the underlying element of `<Field/>`, specify a `component` prop. It can either be a string like `select` or another React component.
728
729```js
730import React from 'react';
731import { Formik, Field } from 'formik';
732
733const Example = () => (
734 <div>
735 <h1>My Form</h1>
736 <Formik
737 initialValues={{ email: '', color: 'red', firstName: '' }}
738 onSubmit={(values, actions) => {
739 setTimeout(() => {
740 alert(JSON.stringify(values, null, 2))
741 actions.setSubmitting(false)
742 }, 1000);
743 }}
744 render={(props: FormikProps<Values>) =>
745 <form onSubmit={props.handleSubmit}>
746 <Field type="email" name="email" placeholder="Email" />
747 <Field component="select" name="color" >
748 <option value="red">Red</option>
749 <option value="green">Green</option>
750 <option value="blue">Blue</option>
751 </Field>
752 <Field component={CustomInputComponent} name="firstName" />
753 <button type="submit">Submit</button>
754 </form>}
755 />
756 </div>
757);
758
759const CustomInputComponent: React.SFC<FormikProps<Values> & CustomInputProps> => ({
760 field, // { name, value, onChange, onBlur }
761 form: { touched, errors } // also values, setXXXX, handleXXXX, dirty, isValid, status, etc.
762 ...props
763}) => (
764 <div>
765 <input
766 type="text"
767 {...field}
768 {...props}
769 />
770 {touched[name] && errors[name] && <div className="error">{errors[name]}</div>}
771 </div>
772)
773```
774
775### `<Form />`
776
777Like `<Field/>`, `<Form/>` is a helper component you can use to save time. It is tiny wrapper around `<form onSubmit={context.formik.handleSubmit} />`. This means you don't need to explictly type out `<form onSubmit={props.handleSubmit}/>` if you don't want to.
778
779**ReactDOM only**
780
781```jsx
782import React from 'react';
783import { Formik, Field, Form } from 'formik';
784
785const Example = () => (
786 <div>
787 <h1>My Form</h1>
788 <Formik
789 initialValues={{ email: '', color: 'red' }}
790 onSubmit={(values, actions) => {
791 setTimeout(() => {
792 alert(JSON.stringify(values, null, 2))
793 actions.setSubmitting(false)
794 }, 1000);
795 }}
796 component={MyForm}
797 />
798 </div>
799);
800
801const MyForm = () =>
802 <Form>
803 <Field type="email" name="email" placeholder="Email" />
804 <Field component="select" name="color">
805 <option value="red">Red</option>
806 <option value="green">Green</option>
807 <option value="blue">Blue</option>
808 </Field>
809 <button type="submit">Submit</button>
810 </Form>;
811```
812
813### `withFormik(options)`
814
815Create a higher-order React component class that passes props and form handlers (the "`FormikBag`") into your component derived from supplied options.
816
817#### `options`
818
819##### `displayName?: string`
820When your inner form component is a stateless functional component, you can use the `displayName` option to give the component a proper name so you can more easily find it in [React DevTools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en). If specified, your wrapped form will show up as `Formik(displayName)`. If omitted, it will show up as `Formik(Component)`. This option is not required for class components (e.g. `class XXXXX extends React.Component {..}`).
821
822##### `enableReinitialize?: boolean`
823
824Default is `false`. Control whether Formik should reset the form if the wrapped component props change (using deep equality).
825
826##### `handleSubmit: (values: Values, formikBag: FormikBag) => void`
827Your form submission handler. It is passed your forms [`values`] and the "FormikBag", which includes an object containing a subset of the [injected props and methods](/#injected-props-and-methods) (i.e. all the methods with names that start with `set<Thing>` + `resetForm`) and any props that were passed to the the wrapped component.
828
829###### The "FormikBag":
830
831- `props` (props passed to the wrapped component)
832- [`resetForm`]
833- [`setErrors`]
834- [`setFieldError`]
835- [`setFieldTouched`]
836- [`setFieldValue`]
837- [`setStatus`]
838- [`setSubmitting`]
839- [`setTouched`]
840- [`setValues`]
841
842Note: [`errors`], [`touched`], [`status`] and all event handlers are NOT included in the `FormikBag`.
843
844##### `isInitialValid?: boolean | (props: Props) => boolean`
845
846Default is `false`. Control the initial value of [`isValid`] prop prior to mount. You can also pass a function. Useful for situations when you want to enable/disable a submit and reset buttons on initial mount.
847
848##### `mapPropsToValues?: (props: Props) => Values`
849
850If this option is specified, then Formik will transfer its results into updatable form state and make these values available to the new component as [`props.values`][`values`]. If `mapPropsToValues` is not specified, then Formik will map all props that are not functions to the inner component's [`props.values`][`values`]. That is, if you omit it, Formik will only pass `props` where `typeof props[k] !== 'function'`, where `k` is some key.
851
852Even if your form is not receiving any props from its parent, use `mapPropsToValues` to initialize your forms empty state.
853
854##### `validate?: (values: Values, props: Props) => FormikError<Values> | Promise<any>`
855
856_Note: I suggest using [`validateSchema`] and Yup for validation. However, `validate` is a dependency-free, straightforward way to validate your forms._
857
858Validate the form's [`values`] with function. This function can either be:
859
8601. Synchronous and return an [`errors`] object.
861
862```js
863// Synchronous validation
864const validate = (values, props) => {
865 let errors = {};
866
867 if (!values.email) {
868 errors.email = 'Required';
869 } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
870 errors.email = 'Invalid email address';
871 }
872
873 //...
874
875 return errors;
876};
877```
878- Asynchronous and return a Promise that's error is an [`errors`] object
879
880```js
881// Async Validation
882const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
883
884const validate = (values, props) => {
885 return sleep(2000).then(() => {
886 let errors = {};
887 if (['admin', 'null', 'god'].includes(values.username)) {
888 errors.username = 'Nice try';
889 }
890 // ...
891 if (Object.keys(errors).length) {
892 throw errors;
893 }
894 });
895};
896```
897
898##### `validateOnBlur?: boolean`
899
900Default is `true`. Use this option to run validations on `blur` events. More specifically, when either [`handleBlur`], [`setFieldTouched`], or [`setTouched`] are called.
901
902##### `validateOnChange?: boolean`
903
904Default is `true`. Use this option to tell Formik to run validations on `change` events and `change`-related methods. More specifically, when either [`handleChange`], [`setFieldValue`], or [`setValues`] are called.
905
906##### `validationSchema?: Schema | ((props: Props) => Schema)`
907
908[A Yup schema](https://github.com/jquense/yup) or a function that returns a Yup schema. This is used for validation. Errors are mapped by key to the inner component's [`errors`]. Its keys should match those of [`values`].
909
910#### Injected props and methods
911
912These are identical to the props of `<Formik render={props => ...} />`
913
914## Guides
915
916### React Native
917
918**Formik is 100% compatible with React Native and React Native Web.** However, because of differences between ReactDOM's and React Native's handling of forms and text input, there are two differences to be aware of. This section will walk you through them and what I consider to be best practices.
919
920Before going any further, here's a super minimal gist of how to use Formik with React Native that demonstrates the key differences:
921
922```js
923// Formik x React Native example
924import React from 'react';
925import { Button, TextInput, View } from 'react-native';
926import { withFormik } from 'formik';
927
928const enhancer = withFormik(
929 {
930 /*...*/
931 }
932);
933
934const MyReactNativeForm = props =>
935 <View>
936 <TextInput
937 onChangeText={text => props.setFieldValue('email', text)}
938 value={props.values.email}
939 />
940 <Button onPress={props.handleSubmit} title="Submit" /> //
941 </View>;
942
943export default enhancer(MyReactNativeForm);
944```
945
946As you can see above, the notable differences between using Formik with React DOM and React Native are:
947
9481. Formik's `props.handleSubmit` is passed to a `<Button onPress={...}/>` instead of HTML `<form onSubmit={...}/>` component (since there is no `<form/>` element in React Native).
9492. `<TextInput />` uses Formik's `props.setFieldValue` instead of `props.handleChange`. To understand why, see the discussion below.
950
951
952#### Why use `setFieldValue` instead of `handleChange`?
953
954'cuz [`handleChange`] will not work in React Native...
955
956```js
957import { Button, TextInput, View } from 'react-native';
958import { Formik } from 'formik';
959
960const MyReactNativeForm = props => (
961 <View>
962 <Formik
963 onSubmit={(values, actions) => {
964 setTimeout(() => {
965 console.log(JSON.stringify(values, null, 2))
966 actions.setSubmitting(false)
967 }, 1000);
968 }}
969 render={props =>
970 <View>
971 <TextInput
972 name="email"
973 onChangeText={props.handleChange} // this WILL NOT WORK IN RN
974 value={props.values.email}
975 />
976 <Button onPress={props.handleSubmit} />
977 </View>
978 }
979 />
980 </View>
981)
982```
983
984The reason is that Formik's [`handleChange`] function expects its first argument to be synthetic DOM event where the `event.target` is the DOM input element and `event.target.id` or `event.target.name` matches the field to be updated. Without this, [`handleChange`] will do nothing.
985
986In React Native, neither [`<TextInput />`](https://facebook.github.io/react-native/docs/textinput.html)'s [`onChange`](https://facebook.github.io/react-native/docs/textinput.html#onchange) nor [`onChangeText`](https://facebook.github.io/react-native/docs/textinput.html#onchange) callbacks pass such an event or one like it to its callback. Instead, they do the following *(emphasis added)*:
987
988> [`onChange?: function`](https://facebook.github.io/react-native/docs/textinput.html#onchange)
989> Callback that is called when the text input's text changes.
990>
991> [`onChangeText?: function`](https://facebook.github.io/react-native/docs/textinput.html#onchangetext)
992> Callback that is called when the text input's text changes. **Changed text is passed as an argument to the callback handler.**
993
994However, Formik works just fine if you use `props.setFieldValue`! Philisophically, just treat React Native's `<TextInput/>` the same way you would any other 3rd party custom input element.
995
996In conclusion, the following WILL work in React Native:
997
998```js
999// ...
1000// this works.
1001export const MyReactNativeForm = props =>
1002 <View>
1003 <TextInput
1004 onChangeText={text => props.setFieldValue('email', text)}
1005 value={props.values.email}
1006 />
1007 <Button onPress={props.handleSubmit} />
1008 </View>;
1009// ...
1010```
1011
1012#### Avoiding a Render Callback
1013
1014If you are like me and do not like render callbacks, I suggest treating React Native's `<TextInput/>` as if it were another 3rd party custom input element:
1015
1016 - Write your own class wrapper around the custom input element
1017 - Pass the custom component [`props.setFieldValue`][`setFieldValue`] instead of [`props.handleChange`][`handleChange`]
1018 - Use a custom change handler callback that calls whatever you passed-in `setFieldValue` as (in this case we'll match the React Native TextInput API and call it `this.props.onChangeText` for parity).
1019
1020```js
1021// FormikReactNativeTextInput.js
1022import * as React from 'react'
1023import { TextInput } from 'react-native'
1024
1025export default class FormikReactNativeTextInput extends React.Component {
1026 handleChange = (value: string) => {
1027 // remember that onChangeText will be Formik's setFieldValue
1028 this.props.onChangeText(this.props.name, value)
1029 }
1030
1031 render() {
1032 // we want to pass through all the props except for onChangeText
1033 const { onChangeText, ...otherProps } = this.props
1034 return (
1035 <TextInput
1036 onChangeText={this.handleChange}
1037 {...otherProps} // IRL, you should be more explicit when using TS
1038 />
1039 );
1040 }
1041}
1042```
1043
1044
1045Then you could just use this custom input as follows:
1046
1047```tsx
1048// MyReactNativeForm.js
1049import { View, Button } from 'react-native'
1050import { FormikReactNativeTextInput as TextInput } from './FormikReactNativeTextInput'
1051import { Formik } from 'formik'
1052
1053
1054const MyReactNativeForm = props => (
1055 <View>
1056 <Formik
1057 onSubmit={(values, actions) => {
1058 setTimeout(() => {
1059 console.log(JSON.stringify(values, null, 2))
1060 actions.setSubmitting(false)
1061 }, 1000);
1062 }}
1063 render={props =>
1064 <View>
1065 <TextInput
1066 name="email"
1067 onChangeText={props.setFieldValue}
1068 value={props.values.email}
1069 />
1070 <Button onPress={props.handleSubmit} />
1071 </View>
1072 }
1073 />
1074 </View>
1075)
1076
1077export default MyReactNativeForm
1078```
1079
1080## Organizations and projects using Formik
1081
1082[List of organizations and projects using Formik](https://github.com/jaredpalmer/formik/issues/87)
1083
1084## Authors
1085
1086- Jared Palmer [@jaredpalmer](https://twitter.com/jaredpalmer)
1087- Ian White [@eonwhite](https://twitter.com/eonwhite)
1088
1089## Contributors
1090
1091Formik is made with <3 thanks to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):
1092
1093<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
1094| [<img src="https://avatars2.githubusercontent.com/u/4060187?v=4" width="100px;"/><br /><sub>Jared Palmer</sub>](http://jaredpalmer.com)<br />[💬](#question-jaredpalmer "Answering Questions") [💻](https://github.com/jaredpalmer/formik/commits?author=jaredpalmer "Code") [🎨](#design-jaredpalmer "Design") [📖](https://github.com/jaredpalmer/formik/commits?author=jaredpalmer "Documentation") [💡](#example-jaredpalmer "Examples") [🤔](#ideas-jaredpalmer "Ideas, Planning, & Feedback") [👀](#review-jaredpalmer "Reviewed Pull Requests") [⚠️](https://github.com/jaredpalmer/formik/commits?author=jaredpalmer "Tests") | [<img src="https://avatars0.githubusercontent.com/u/109324?v=4" width="100px;"/><br /><sub>Ian White</sub>](https://www.stardog.io)<br />[💬](#question-eonwhite "Answering Questions") [🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Aeonwhite "Bug reports") [💻](https://github.com/jaredpalmer/formik/commits?author=eonwhite "Code") [📖](https://github.com/jaredpalmer/formik/commits?author=eonwhite "Documentation") [🤔](#ideas-eonwhite "Ideas, Planning, & Feedback") [👀](#review-eonwhite "Reviewed Pull Requests") | [<img src="https://avatars0.githubusercontent.com/u/829963?v=4" width="100px;"/><br /><sub>Andrej Badin</sub>](http://andrejbadin.com)<br />[💬](#question-Andreyco "Answering Questions") [🐛](https://github.com/jaredpalmer/formik/issues?q=author%3AAndreyco "Bug reports") [📖](https://github.com/jaredpalmer/formik/commits?author=Andreyco "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/91115?v=4" width="100px;"/><br /><sub>Adam Howard</sub>](http://adz.co.de)<br />[💬](#question-skattyadz "Answering Questions") [🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Askattyadz "Bug reports") [🤔](#ideas-skattyadz "Ideas, Planning, & Feedback") [👀](#review-skattyadz "Reviewed Pull Requests") | [<img src="https://avatars1.githubusercontent.com/u/6711845?v=4" width="100px;"/><br /><sub>Vlad Shcherbin</sub>](https://github.com/VladShcherbin)<br />[💬](#question-VladShcherbin "Answering Questions") [🐛](https://github.com/jaredpalmer/formik/issues?q=author%3AVladShcherbin "Bug reports") [🤔](#ideas-VladShcherbin "Ideas, Planning, & Feedback") | [<img src="https://avatars3.githubusercontent.com/u/383212?v=4" width="100px;"/><br /><sub>Brikou CARRE</sub>](https://github.com/brikou)<br />[🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Abrikou "Bug reports") [📖](https://github.com/jaredpalmer/formik/commits?author=brikou "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/5314713?v=4" width="100px;"/><br /><sub>Sam Kvale</sub>](http://skvale.github.io)<br />[🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Askvale "Bug reports") [💻](https://github.com/jaredpalmer/formik/commits?author=skvale "Code") [⚠️](https://github.com/jaredpalmer/formik/commits?author=skvale "Tests") |
1095| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
1096| [<img src="https://avatars0.githubusercontent.com/u/13765558?v=4" width="100px;"/><br /><sub>Jon Tansey</sub>](http://jon.tansey.info)<br />[🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Ajontansey "Bug reports") [💻](https://github.com/jaredpalmer/formik/commits?author=jontansey "Code") | [<img src="https://avatars0.githubusercontent.com/u/6819171?v=4" width="100px;"/><br /><sub>Tyler Martinez</sub>](http://slightlytyler.com)<br />[🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Aslightlytyler "Bug reports") [📖](https://github.com/jaredpalmer/formik/commits?author=slightlytyler "Documentation") |
1097<!-- ALL-CONTRIBUTORS-LIST:END -->
1098
1099This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
1100
1101---
1102
1103MIT License.
1104
1105---
1106
1107[`displayName`]: #displayname-string
1108[`handleSubmit`]: #handlesubmit-payload-formikbag--void
1109[`FormikBag`]: #the-formikbag
1110[`isInitialValid`]: #isinitialvalid-boolean--props-props--boolean
1111[`mapPropsToValues`]: #mappropstovalues-props--props
1112[`validate`]: #validate-values-values-props-props--formikerrorvalues--promiseany
1113[`validateOnBlur`]: #validateonblur-boolean
1114[`validateOnChange`]: #validateonchange-boolean
1115[`validationSchema`]: #validationschema-schema--props-props--schema
1116
1117[Injected props and methods]: #injected-props-and-methods
1118
1119[`dirty`]: #dirty-boolean
1120[`errors`]: #errors--field-string-string-
1121[`handleBlur`]: #handleblur-e-any--void
1122[`handleChange`]: #handlechange-e-reactchangeeventany--void
1123[`handleReset`]: #handlereset---void
1124[`handleSubmit`]: #handlesubmit-e-reactformeventhtmlformevent--void
1125[`isSubmitting`]: #issubmitting-boolean
1126[`isValid`]: #isvalid-boolean
1127[`resetForm`]: #resetform-nextprops-props--void
1128[`setErrors`]: #seterrors-fields--field-string-string---void
1129[`setFieldError`]: #setfielderror-field-string-errormsg-string--void
1130[`setFieldTouched`]: #setfieldtouched-field-string-istouched-boolean--void
1131[`setFieldValue`]: #setfieldvalue-field-string-value-any--void
1132[`setStatus`]: #setstatus-status-any--void
1133[`setSubmitting`]: #setsubmitting-boolean--void
1134[`setTouched`]: #settouched-fields--field-string-boolean---void
1135[`setValues`]: #setvalues-fields--field-string-any---void
1136[`status`]: #status-any
1137[`touched`]: #touched--field-string-boolean-
1138[`values`]: #values--field-string-any-