Textarea input fields in Chakra UI wont submit to react hook form

I am using nextjs (v13), react (v18) chakraUI and react hook form.

If I use Inputs (only), I can submit this form. If I change the description field to be a Textarea (from ChakraUI), the form displays on the page, but will not submit. I get no errors in the console - I can't see what's causing the issue.

Is it possible to submit data from a Textarea via react-hook-form?

import * as React from "react"
import { gql } from "@apollo/client"
import { Button, Stack, Textarea, Text } from "@chakra-ui/react"
import { useRouter } from "next/router"
import { useCreateIssueGroupMutation } from "lib/graphql"
import { useForm } from "lib/hooks/useForm"
import Yup from "lib/yup"
import { ButtonGroup } from "./ButtonGroup"
import { Form } from "./Form"
import { FormError } from "./FormError"
import { Input } from "./Input"
import { Modal } from "antd"
const _ = gql` mutation CreateIssueGroup($data: IssueGroupInput!) { createIssueGroup(data: $data) { id } }
`
interface Props { onClose: () => void
}
const IssueGroupSchema = Yup.object().shape({ title: Yup.string().required(), description: Yup.string().required(),
})
export function AdminCreateIssueGroupForm(props: Props) { const router = useRouter() const [createIssueGroup] = useCreateIssueGroupMutation() const defaultValues = { title: "", description: "", } const form = useForm({ defaultValues, schema: IssueGroupSchema }) const handleSubmit = (data: Yup.InferType<typeof IssueGroupSchema>) => { return form.handler(() => createIssueGroup({ variables: { data: { ...data } } }), { onSuccess: (res, toast) => { toast({ description: "Issue group created" }) form.reset() props.onClose() }, }) } return ( <Form {...form} onSubmit={handleSubmit}> <Stack> <Input name="title" label="Title" /> // this input works and allows me to submit the form {/* <Input name="description" label="Description" /> */} // the next 2 lines do not work. The page renders but the form does not submit <Text mb='8px' fontWeight="medium" fontSize="sm" > Description</Text> <Textarea name="description" rows={4} /> <FormError /> <ButtonGroup> <Button onClick={props.onClose}>Cancel</Button> <Button type="submit" isLoading={form.formState.isSubmitting} isDisabled={form.formState.isSubmitting} color="brand.white" fontWeight="normal" backgroundColor="brand.orange" _hover={{ backgroundColor: "brand.green", color: "brand.white", }} > Create </Button> </ButtonGroup> </Stack> </Form> )
}

My Form component has:

import * as React from "react"
import type { FieldValues, UseFormReturn } from "react-hook-form"
import { FormProvider, useFormContext } from "react-hook-form"
import { Box } from "@chakra-ui/react"
import * as Sentry from "@sentry/nextjs"
import { useToast } from "lib/hooks/useToast"
interface FormContainerProps { onSubmit?: (values: any) => Promise<any> | any onBlur?: (values: any) => Promise<any> | any
}
const FormContainer: React.FC<FormContainerProps> = (props) => { const toast = useToast() const { handleSubmit } = useFormContext() const onSubmit = async (values: any) => { try { if (props.onBlur) { return await props.onBlur(values) } if (props.onSubmit) { return await props.onSubmit(values) } } catch (e) { console.log(e) Sentry.captureException(e) toast({ title: "Application error", description: "Something went wrong. We have been notified!", status: "error", }) return } } return ( <Box as="form" w="100%" {...(props.onSubmit && { onSubmit: handleSubmit(onSubmit) })} {...(props.onBlur && { onBlur: handleSubmit(onSubmit) })} > {props.children} </Box> )
}
interface Props<T extends FieldValues> extends UseFormReturn<T>, FormContainerProps { children: React.ReactNode isDisabled?: boolean
}
export function Form<T extends FieldValues>({ onSubmit, onBlur, isDisabled, ...props }: Props<T>) { return ( <FormProvider {...props}> <fieldset disabled={isDisabled}> <FormContainer {...{ onSubmit, onBlur }}>{props.children}</FormContainer> </fieldset> </FormProvider> )
}

Input has:

import * as React from "react"
import { useFormContext } from "react-hook-form"
import type { InputProps } from "@chakra-ui/react";
import { FormControl, Input as CInput } from "@chakra-ui/react"
import { InputError } from "./InputError"
import { InputLabel } from "./InputLabel"
interface Props extends InputProps { name: string label?: string subLabel?: string
}
export const Input = ({ label, subLabel, ...props }: Props) => { const { register, formState: { errors }, } = useFormContext() const fieldError = errors?.[props.name] return ( <FormControl isInvalid={!!fieldError} isRequired={props.isRequired}> <InputLabel label={label} subLabel={subLabel} name={props.name} /> <CInput {...register(props.name)} mb={0} {...props} /> <InputError error={fieldError} /> </FormControl> )
}

1 Answer

Each form component connected to React Hook Form needs to receive a register or be wrapped by a Controller component. Your input component receives this by useFormContext as you mentioned:

<CInput {...register(props.name)} mb={0} {...props} />

However, TextArea component doesn't receive anything from Hook Form, in that case, you need to use the same register('').

An example of this implementation (live on CodeSandbox):

function App() { const { register, handleSubmit } = useForm({ defaultValues: { title: "", description: "" } }); return ( <> <form onSubmit={handleSubmit((data) => console.log(data))}> <Heading>Welcome to Chakra + TS</Heading> <p>Title</p> <Input {...register("title")} /> <p>Description</p> <Textarea {...register("description")} /> <Button type="submit">Submit</Button> </form> </> );
}

Useful links:

6

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like