import React from 'react';
2 import ReactDOM from 'react-dom';
3 import { Formik, Form, useField } from 'formik';
4 import * as Yup from 'yup';
5
6 const MyTextInput = ({ label, ...props }) => {
7 // useField() returns [formik.getFieldProps(), formik.getFieldMeta()]
8 // which we can spread on <input>. We can use field meta to show an error
9 // message if the field is invalid and it has been touched (i.e. visited)
10 const [field, meta] = useField(props);
11 return (
12 <>
13 <label htmlFor={props.id || props.name}>{label}</label>
14 <input className="text-input" {...field} {...props} />
15 {meta.touched && meta.error ? (
16 <div className="error">{meta.error}</div>
17 ) : null}
18 </>
19 );
20 };
21
22 const MyCheckbox = ({ children, ...props }) => {
23 // React treats radios and checkbox inputs differently other input types, select, and textarea.
24 // Formik does this too! When you specify `type` to useField(), it will
25 // return the correct bag of props for you -- a `checked` prop will be included
26 // in `field` alongside `name`, `value`, `onChange`, and `onBlur`
27 const [field, meta] = useField({ ...props, type: 'checkbox' });
28 return (
29 <div>
30 <label className="checkbox-input">
31 <input type="checkbox" {...field} {...props} />
32 {children}
33 </label>
34 {meta.touched && meta.error ? (
35 <div className="error">{meta.error}</div>
36 ) : null}
37 </div>
38 );
39 };
40
41 const MySelect = ({ label, ...props }) => {
42 const [field, meta] = useField(props);
43 return (
44 <div>
45 <label htmlFor={props.id || props.name}>{label}</label>
46 <select {...field} {...props} />
47 {meta.touched && meta.error ? (
48 <div className="error">{meta.error}</div>
49 ) : null}
50 </div>
51 );
52 };
53
54 // And now we can use these
55 const SignupForm = () => {
56 return (
57 <>
58 <h1>Subscribe!</h1>
59 <Formik
60 initialValues={{
61 firstName: '',
62 lastName: '',
63 email: '',
64 acceptedTerms: false, // added for our checkbox
65 jobType: '', // added for our select
66 }}
67 validationSchema={Yup.object({
68 firstName: Yup.string()
69 .max(15, 'Must be 15 characters or less')
70 .required('Required'),
71 lastName: Yup.string()
72 .max(20, 'Must be 20 characters or less')
73 .required('Required'),
74 email: Yup.string()
75 .email('Invalid email address')
76 .required('Required'),
77 acceptedTerms: Yup.boolean()
78 .required('Required')
79 .oneOf([true], 'You must accept the terms and conditions.'),
80 jobType: Yup.string()
81 .oneOf(
82 ['designer', 'development', 'product', 'other'],
83 'Invalid Job Type'
84 )
85 .required('Required'),
86 })}
87 onSubmit={(values, { setSubmitting }) => {
88 setTimeout(() => {
89 alert(JSON.stringify(values, null, 2));
90 setSubmitting(false);
91 }, 400);
92 }}
93 >
94 <Form>
95 <MyTextInput
96 label="First Name"
97 name="firstName"
98 type="text"
99 placeholder="Jane"
100 />
101
102 <MyTextInput
103 label="Last Name"
104 name="lastName"
105 type="text"
106 placeholder="Doe"
107 />
108
109 <MyTextInput
110 label="Email Address"
111 name="email"
112 type="email"
113 placeholder="jane@formik.com"
114 />
115
116 <MySelect label="Job Type" name="jobType">
117 <option value="">Select a job type</option>
118 <option value="designer">Designer</option>
119 <option value="development">Developer</option>
120 <option value="product">Product Manager</option>
121 <option value="other">Other</option>
122 </MySelect>
123
124 <MyCheckbox name="acceptedTerms">
125 I accept the terms and conditions
126 </MyCheckbox>
127
128 <button type="submit">Submit</button>
129 </Form>
130 </Formik>
131 </>
132 );
133 };