How to use react-select with Formik (Typescript)
Jasser Mark Arioste
The react-select package is a great library to use when building awesome interactive select components. But how do we integrate it with Formik and Typescript?
Here's how I did it.
We'll create a custom component that uses Formik hooks to set the value. We also define the OptionType
and GroupedOption
so that it'll be easier to manage the types.
Step 1- Import the Dependencies: #
// components/FormikReactSelect.tsx import { useField, useFormikContext } from "formik"; import React from "react"; import Select from "react-select"; import { StateManagerProps } from "react-select/dist/declarations/src/useStateManager"; ...
123456
Step 2 - Define the Props for Our App #
... // components/FormikReactSelect.tsx // define the OptionType for your app type MyOption = { label: string; value: any; }; //define the group option type type GroupedOption = { label: string; // group label options: MyOption[]; }; // component props type Props = { name: string; } & Omit< StateManagerProps<MyOption, false | true, GroupedOption>, "value" | "onChange" >; ...
1234567891011121314151617181920
Explanation:
Lines 3-6 & 6-8: We define the OptionType and GroupedOption type:
Line 13-18: We define the component props. The name
prop is for the Formik field name.
We intersect it with StateManagerProps
from react-select
to so that we can still use the props for the Select
component.
We omit value
and onChange
since we're using Formik hooks to set the field value. Formik will manage the state for us.
Step 3 - Define the FormikReactSelect
Component
#
... const FormikReactSelect = (props: Props) => { const { name, ...restProps } = props; const [field] = useField(name); const { setFieldValue } = useFormikContext(); //flatten the options so that it will be easier to find the value const flattenedOptions = props.options?.flatMap((o) => { const isNotGrouped = "value" in o; if (isNotGrouped) { return o; } else { return o.options; } }); //get the value using flattenedOptions and field.value const value = flattenedOptions?.filter((o) => { const isArrayValue = Array.isArray(field.value); if (isArrayValue) { const values = field.value as Array<any>; return values.includes(o.value); } else { return field.value === o.value; } }); return ( <Select {...restProps} value={value} // onChange implementation onChange={(val) => { //here I used explicit typing but there maybe a better way to type the value. const _val = val as MyOption[] | MyOption; const isArray = Array.isArray(_val); if (isArray) { const values = _val.map((o) => o.value); setFieldValue(name, values); } else { setFieldValue(name, _val.value); } }} /> ); }; export default FormikReactSelect;
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
Usage #
We have to use the <Formik/>
provider component for this technique to work. I recommend to use it since I find it cleaner and more maintainable over the useFormik
hook.
// components/HomePage.tsx import FormikReactSelect from "../components/FormikReactSelect"; import { Form, Formik } from "formik"; export default function HomePage() { const options = [ { value: "chocolate", label: "Chocolate" }, { value: "strawberry", label: "Strawberry" }, { value: "vanilla", label: "Vanilla" }, ]; return ( <> <Formik onSubmit={(values) => console.log(values)} initialValues={{ favoriteFruits: ["chocolate"], }} > <Form> <FormikReactSelect name="favoriteFruits" isMulti={true} options={options} /> <button type="submit">Submit</button> </Form> </Formik> </> ); }
1234567891011121314151617181920212223242526272829
Explanation:
Lines 5-9: We define the options for the select component:
Line 15: Notice that the initialValues
are of type string[]
but the options are MyOption[]
type. Most production apps doesn't use objects for values. That's we extract the o.value
from on the onChange
handler from Step 3.
Code #
The full code can be accessed at jmarioste/react-select-formik-tutorial.
Conclusion #
We learned how to integrate react-select with Formik by using Formik hooks and Formik context provider.
If you like this tutorial, please leave a like or share this article. For future tutorials like this, please subscribe to our newsletter or follow me on Twitter.