⚛ Formik
11 Nov, 2021
👋 FYI, this note is over 6 months old. Some of the content may be out of date.
On this page
Simple example Jump to heading
import { Formik, ErrorMessage, ErrorMessage, FormikHelpers, Form } from 'formik'
interface SignupFormValues {
email: string
password: string
firstName: string
lastName: string
}
export const SignupForm = () => {
const [formError, setFormError] = useState<string>('')
return (
<Formik
initialValues={{
email: '',
password: '',
firstName: '',
lastName: '',
}}
onSubmit={async (
values: SignupFormValues,
actions: FormikHelpers<SignupFormValues>
) => {
// submit form data to API
}}
>
{({ handleChange, handleBlur, values, isSubmitting, getFieldProps }) => (
<Form>
<div>
<label htmlFor="firstName">First name</label>
<input
type="text"
autoComplete="given-name"
{...getFieldProps('firstName')}
/>
<ErrorMessage name="firstName">
{(msg) => <div>{msg}</div>}
</ErrorMessage>
</div>
<div>
<label htmlFor="lastName">Last name</label>
<input
name="lastName"
autoComplete="family-name"
{...getFieldProps('lastName')}
/>
<ErrorMessage name="lastName">
{(msg) => <div>{msg}</div>}
</ErrorMessage>
</div>
<div>
<label htmlFor="email">Email address</label>
<input type="email" {...getFieldProps('email')} />
<ErrorMessage name="email">
{(msg) => <div>{msg}</div>}
</ErrorMessage>
</div>
<div>
<label htmlFor="password">Password</label>
<input type="password" {...getFieldProps('password')} />
<ErrorMessage name="password">
{(msg) => <div>{msg}</div>}
</ErrorMessage>
</div>
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
)
}
Using Yup for validation Jump to heading
import React from 'react'
import { Formik } from 'formik'
interface SignupFormValues {
email: string
password: string
firstName: string
lastName: string
}
const InviteSchema = Yup.object().shape({
email: Yup.string().email('Invalid email').required('Required'),
password: Yup.string().required('Required').min(8).max(200),
firstName: Yup.string().required('Required'),
lastName: Yup.string(),
})
Common patterns Jump to heading
Loading state Jump to heading
Use the useToggle
hook to manipulate loading state for your form. When used correctly, the Button
component will show a loading indicator when the form is submitting.
// initialise the state
const [formSubmitting, , setFormSubmitting] = useToggle()
// change it when the user submits the form
onSubmit={async (values: FormValues) => {
setFormSubmitting(true) // <-- here
try {
// call your API to submit the form
} catch (error: unknown) {
// catch any errors
let errorMessage = 'error.unknown'
if (typeof error === 'string') {
errorMessage = error.toUpperCase()
} else if (error instanceof Error) {
errorMessage = error.message
}
setFormError(errorMessage)
setFormSubmitting(false) // <-- here
}
}}
// use it on the button
<Button
type="submit"
isLoading={formSubmitting}
>
Submit
</Button>
Submission errors Jump to heading
Use a useState
hook to set any errors that occur during form validation.
// initialise the state
const [formError, setFormError] = useState<string>('')
// set the error when the form is submitted
onSubmit={async (values: FormValues) => {
setFormSubmitting(true)
try {
// call your API to submit the form
} catch (error: unknown) {
// catch any errors
let errorMessage = 'error.unknown'
if (typeof error === 'string') {
errorMessage = error.toUpperCase()
} else if (error instanceof Error) {
errorMessage = error.message
}
setFormError(errorMessage) // <-- here
setFormSubmitting(false)
}
}}
// Render a message if there are errors
{formError && <Alert variant="error">{formError}</Alert>}
Another aspect is to “disable” the submit button when there are validation errors. Use the isValid
prop from Formik to determine if the form is valid, then set the isDisabled
prop on the Button
component. This will prevent the button from being clicked and show a useful message to the user notifying them of the issue.
<Button
type="submit"
sx={{ mt: 2 }}
isLoading={formSubmitting}
isDisabled={!isValid}
disabledText="Please fix the form validation errors"
>
Submit
</Button>
Validation Jump to heading
Use the Yup
library to validate the form. It is used in many forms in the app.
Create your form schema:
const FormSchema = Yup.object().shape({
email: Yup.string().email('Invalid email').required('Required'),
password: passwordValidation,
})
← Back home