React Hook Form
Set up React Hook Form for forms in an Expo app with ReadyNative: Form + Field on @/ui Input, zod resolver · Expo Go OK
Expo Go: yes
Runs in Expo Go; no dev build needed for this module.
React Hook Form plus a zod resolver, wrapped in two small components under src/components/form/ so your screens stay on @/components/ui. I'd pick it over forms/none as soon as a form has more than two fields or any validation worth naming - you get uncontrolled inputs, one schema per form and error messages wired into the kit's Input for free. Field is the contract here: it binds the kit's Input through Controller and shows the validation message as its error prop, so you never style an error state by hand.
Setup
bun run setup --forms react-hook-formThat's it - setup adds src/components/form/form.tsx (<Form form={…}>, a FormProvider wrapper), src/components/form/field.tsx, the barrel index.ts, and a test; @hookform/resolvers/zod is zod 4 compatible. With --with-examples you also get the /examples/form route with a zod schema.
Usage
One schema, one useForm, one <Form>:
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { Field, Form } from "@/components/form";
import { Button } from "@/components/ui";
const schema = z.object({ email: z.email(), name: z.string().min(1) });
type Values = z.infer<typeof schema>;
const form = useForm<Values>({ resolver: zodResolver(schema), defaultValues });
<Form form={form}>
<Field<Values> name="email" label="Email" keyboardType="email-address" />
<Field<Values> name="name" label="Name" />
<Button onPress={() => void form.handleSubmit(onValid)()}>Save</Button>
</Form>;Field accepts every InputProps except value, onChangeText and error - those are what it wires up for you.
Gotchas
- Expo Go works - it's pure JS.
- Set up with
--with-examples? Copysrc/screens/examples/form-example-screen.tsxwhen you start a real form; it's the full loop from schema to submit. - Swapping stacks:
bun run setup --forms nonedeletessrc/components/form, the example and both dependencies. Screens that usedFieldneed rewriting as controlledInputs.
Remove it
While modules/ exists (a tree set up with --keep-modules), setup does all of it:
bun run setup --forms none --yes --keep-modulesIn a finalized tree setup is a stub, so you undo it by hand. Here is everything this module added:
- Delete the files that are still there (the demo screens are gone already unless you set up with
--with-examples):src/app/examples/form.tsx,src/components/form/__tests__/field.test.tsx,src/components/form/field.tsx,src/components/form/form.tsx,src/components/form/index.ts,src/screens/examples/form-example-screen.tsx. - Uninstall the dependencies:
bun remove @hookform/resolvers react-hook-form. - Check it:
bun run typecheckandbun run lintpoint at anything that still imports the removed files;bun run gen:graphrefreshesdocs/ARCHITECTURE.md.
Reference
Everything below is generated from modules/forms/react-hook-form/module.json - the same file bun run setup reads, so it is what actually lands in your repo.
Install
bun run setup --forms react-hook-formModule id: forms/react-hook-form (the default for this category).
Dependencies
| Package | Version | Kind |
|---|---|---|
@hookform/resolvers | ^5.9.1 | dependency |
react-hook-form | ^7.88.0 | dependency |
Files
6 files copied to the project root
src/app/examples/form.tsxsrc/components/form/__tests__/field.test.tsxsrc/components/form/field.tsxsrc/components/form/form.tsxsrc/components/form/index.tssrc/screens/examples/form-example-screen.tsx