Resources:
- Formik tutorial
- useField Formik hook with Typescript
- Using Chakra UI with Formik
- Prop 'id' did not match problem
foreword
Hello everyone.
I will be using create next-app
throughout the post but everything in here is appliable to regular React (CRA) applications.
I expect you to be familiar with Chakra UI and Formik
Let's get started =)
Let's start with creating a new NextJS app:
yarn create next-app MyNextApp --typescript
Open created folder in your IDE, then install Formik and Chakra UI
yarn add @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4 formik
Next we create a new folder components
and a file named CustomInput.tsx
Inside that file create a new Functional component named CustomInput
:
export const CustomInput: FC = ({ label, ...props }) => {
const [field, meta] = useField(props);
return (
<FormControl isInvalid={meta.touched && !!meta.error}>
<FormLabel>
{label}
</FormLabel>
<Input {...field} />
</FormControl>
);
}
At this moment Typescript will yell at us saying it doesn't know what're the label
and props
, we need to explain to that silly what those things are. So we need an interface which can be written two ways: either by extending JSX.IntrinsicElements['input']
interface or by intersecting FieldHookConfig<string>
type:
// intersecting
interface ICustomFieldProps {
label: string;
}
// FieldHookConfig accepts value type as an argument,
// it is 'string' for input elements
export const CustomInput: FC<FieldHookConfig<string> & ICustomFieldProps> = ({
label,
...props
}) => {
...
}
// extending
interface ICustomFieldProps extends JSX.IntrinsicElements['input'] {
label: string;
name: string;
}
export const CustomInput: FC<ICustomFieldProps> = ({ label, ...props }) => {
...
}
Choose whatever way you like.
Now let's create our form. Open pages/index.tsx
file, delete everything in between div
and replace div
with Formik
component.
Add some dummy initialValue
and onSubmit
to Formik
component, place <Form>
and <CustomInput />
inside <Formik>
:
const Home: NextPage = () => {
return (
<Formik initialValues={{name:''}} onSubmit={(val) => alert(val.name)}>
<Form>
<CustomInput name='name' label='name' />
<Button type='submit'>Submit</Button>
</Form>
</Formik>
)
}
export default Home
Ta-da. We now have a form built with Chakra UI and managed by Formik.
But. If you're using NextJS and you open devtools console, you will see a big fat error:
Warning: Prop `id` did not match.
We can fix this by adding id
to our form elements explicitly. Inside CustomInput.tsx
add id
attribute to Input
and FormLabel
components and htmlFor
attribute to FormLabel
:
export const CustomInput: FC<IFormikFieldProps & FieldHookConfig<string>> = ({
label,
...props
}) => {
const [field, meta] = useField(props);
return (
<FormControl isInvalid={meta.touched && !!meta.error}>
<FormLabel
id={`${props.id}-${props.name}-label`}
htmlFor={`${props.id}-${props.name}-input`}
>
{label}
</FormLabel>
<Input
{...field}
id={`${props.id}-${props.name}-input`}
/>
</FormControl>
);
};
Cool. It's done.
notes:
- for select, you must pass
props.children
to Chakra UI'sSelect
component explicitly:
<Select {...field} id={`${props.id}-${props.name}-select`}>
{props.children}
</Select>
- you can add
FormErrorMessage
component, too
Thanks for reading =)
Top comments (0)