Using multiple forms through a single form provider (React Hook Form)
June 09, 2025
Ever had two form elements that you were controlling through useForm, but you want to access the form state for that form throughout the entire page/route and you don't wanna pass props around every component, maybe there is a toast that you want to show based on a certain form state.
Out of the box, React Hook Form provides us a way to access the form state throughout the entire page/route, which is FormProvider
, and useFormContext
.
I will not be describing how to use <FormProvider/>
and useFormContext
in this post, You can read more about them in the official documentation. Rhf itself discourages from using FormProvider
in a nested way.
The main issue arises when you have multiple forms within a layout/page and you want to access the form state for all those forms throughout the entire layout/page.
<FormProvider/>
internally uses React's context api to provide the form.
So what we can do is create our own form provider through the context api.
'use client'; import { createContext, type ReactNode, useContext, useMemo } from 'react'; import { useForm, type UseFormReturn } from 'react-hook-form'; // these are just sample types you can use your preferred schema validation library to define schemas and infer types type SearchSchemaType = { search?: string; }; type InputSchemaType = { input?: string; }; interface IFormsContext { searchFormHook: UseFormReturn<SearchSchemaType>; inputFormHook: UseFormReturn<InputSchemaType>; } const FormsContext = createContext<IFormsContext | null>(null); export const FormsProvider = ({ children }: { children: ReactNode }) => { const searchFormHook = useForm<SearchSchemaType>(); const inputFormHook = useForm<InputSchemaType>(); const value = useMemo( () => ({ searchFormHook, inputFormHook }), [searchFormHook, inputFormHook] ); return ( <FormsContext.Provider value={value}>{children}</FormsContext.Provider> ); }; export const useFormsContext = () => { const context = useContext(FormsContext); if (!context) { throw new Error('useFormsContext must be used within a FormsProvider'); } return context; };
The above can be generalized according to your use-case.
Why Rhf <FormProvider/> doesn't work
React Hook Form's FormProvider
doesn't work well in a nested way because of how it's implemented internally.
You can view the complete source code here.
import React from 'react'; import type { FieldValues, FormProviderProps, UseFormReturn } from './types'; const HookFormContext = React.createContext<UseFormReturn | null>(null); HookFormContext.displayName = 'HookFormContext'; export const FormProvider = < TFieldValues extends FieldValues, TContext = any, TTransformedValues = TFieldValues, >( props: FormProviderProps<TFieldValues, TContext, TTransformedValues>, ) => { const { children, ...data } = props; return ( <HookFormContext.Provider value={data as unknown as UseFormReturn}> {children} </HookFormContext.Provider> ); };
The FormProvider
uses a single React context that can only hold one form's state at a time. When you nest FormProvider
s, each provider overwrites the previous context value because they're using the same context.
Each nested FormProvider
completely replaces the parent's form state in the context. This means that when you try to access form state using useFormContext
in a nested component, you'll only get access to the closest parent's form state, losing access to any outer form states.