ReadyNative

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-form

That'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? Copy src/screens/examples/form-example-screen.tsx when you start a real form; it's the full loop from schema to submit.
  • Swapping stacks: bun run setup --forms none deletes src/components/form, the example and both dependencies. Screens that used Field need rewriting as controlled Inputs.

Remove it

While modules/ exists (a tree set up with --keep-modules), setup does all of it:

bun run setup --forms none --yes --keep-modules

In a finalized tree setup is a stub, so you undo it by hand. Here is everything this module added:

  1. 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.
  2. Uninstall the dependencies: bun remove @hookform/resolvers react-hook-form.
  3. Check it: bun run typecheck and bun run lint point at anything that still imports the removed files; bun run gen:graph refreshes docs/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-form

Module id: forms/react-hook-form (the default for this category).

Dependencies

PackageVersionKind
@hookform/resolvers^5.9.1dependency
react-hook-form^7.88.0dependency

Files

6 files copied to the project root
  • 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

On this page

Get ReadyNative