Despite checkbox fields being an input
once type="checkbox"
is added there are slight changes that make them annoying to deal with. For example rather than value
informing the browser of the value it swaps to checked
being true
or false
.
We'll take a look at both ways to use a checkbox, with Field
and the useField
hook.
The most basic method is rendering Field
as before, but passing in the type="checkbox"
. Here you will get just a normal input
field. It's as simple as you'll get with Formik
and checkboxes but you'll have limited control.
<Field name="acceptTerms" className="mr-2 leading-tight" type="checkbox" />
The Field
variety like we learned is rendered by passing Component
to the field which we pass our MySpecialField
component. One thing that is new is that we need to pass type="checkbox"
to the Field
component itself.
This tells the internals for Formik
that it doesn't need to supply just a value
prop like you would with a text field. It also needs to supply a checked
prop so that the input field will toggle.
<Field name="acceptTerms" type="checkbox" component={MySpecialField} />
Now you will still receive almost the same field
as before except now there will be one extra property on it which is checked: true
. So not only will you get the name
, the value
, but checked
which is how checkboxes are controlled.
{ "name": "acceptTerms", "value": false, "checked": false }
One caveat is you will still need to supply type="checkbox"
to the input
. That doesn't flow through on the field
.
const MySpecialField = ({ field }) => { return ( <label className="text-gray-500 font-bold"> <input {...field} className="mr-2 leading-tight" type="checkbox" /> <span className="text-sm">Accept Terms</span> </label> ); };
Finally the other form is using the useField
hook. The useField
hook can take both a string name
as the only property, or when you need to enable Formik
to understand checkboxes pass in an object with name
and the type
set to checkbox.
Spread the field
on like normal, apply type="checkbox"
and you're checkbox input is all wired up.
const MySpecialFieldHook = () => { const [field] = useField({ name: "acceptTerms", type: "checkbox" }); return ( <label className="text-gray-500 font-bold"> <input {...field} className="mr-2 leading-tight" type="checkbox" /> <span className="text-sm">Accept Terms</span> </label> ); };
One caveat to note is that Formik
will coerce whatever the value
is to be true
or false
, but also maintain the value
.
So for example if the value
for acceptedTerms
was totesAccept
. That would still be what appears on the values
, and checked
would be true. In order to get checked
not to appear as true we would need to set our acceptedTerms
value to be something falsy like null
, false
, undefined
, or 0
.
<Formik initialValues={{ acceptTerms: "totesAccept", }} />
Doing anything but true
and false
will break Formik
unless you're handling all of stuff manually. It is best practice to just use true
and false
for your values and nothing else.
Putting it all together we have 3 checkboxes all driven off of the same value, but rendered multiple ways.
import React from "react"; import { Formik, Form, Field, useField } from "formik"; const MySpecialField = ({ field }) => { return ( <label className="text-gray-500 font-bold"> <input {...field} className="mr-2 leading-tight" type="checkbox" /> <span className="text-sm">Accept Terms</span> </label> ); }; const MySpecialFieldHook = () => { const [field] = useField({ name: "acceptTerms", type: "checkbox" }); return ( <label className="text-gray-500 font-bold"> <input {...field} className="mr-2 leading-tight" type="checkbox" /> <span className="text-sm">Accept Terms</span> </label> ); }; function App() { const handleSubmit = (values) => { console.log(values); }; return ( <div className="App"> <Formik initialValues={{ acceptTerms: false, }} onSubmit={handleSubmit} > {() => { return ( <Form className="h-screen flex content-center flex-col justify-center"> <div className="space-x-4 flex content-center justify-center"> <label className="text-gray-500 font-bold"> <Field name="acceptTerms" className="mr-2 leading-tight" type="checkbox" /> <span className="text-sm">Accept Terms</span> </label> <Field name="acceptTerms" type="checkbox" component={MySpecialField} /> <MySpecialFieldHook /> <button type="submit" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" > Submit </button> </div> </Form> ); }} </Formik> </div> ); } export default App;