> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shipnative.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Forms and Validation

> Build forms with React Hook Form and Zod validation

Shipnative uses **React Hook Form** for form state and **Zod** for validation. This combo gives you type-safe, performant forms with minimal code.

<Tip>
  **For vibecoders:** Just tell your AI "create a form with email and password fields" and it'll generate this pattern.
</Tip>

## React Hook Form: Performant Form Management

[React Hook Form](https://react-hook-form.com/) is a popular library that helps you build forms with less code and better performance. It focuses on uncontrolled components, reducing re-renders and improving overall responsiveness.

### Key Features

* **Performance:** Minimizes re-renders by isolating component updates.
* **Developer Experience:** Simple API with intuitive hooks.
* **Validation Integration:** Seamlessly integrates with schema validation libraries like Zod.
* **Uncontrolled Components:** Leverages native HTML form validation and reduces component re-renders.

### Basic Usage

1. **Import `useForm`:**
   ```typescript theme={null}
   import { useForm, Controller } from 'react-hook-form'
   import { TextField } from '@/../components/TextField' // Assuming a custom TextField component
   import { Button, View } from 'react-native'
   ```
2. **Initialize `useForm`:**
   ```typescript theme={null}
   interface FormData {
     email: string;
     password: string;
   }

   export const LoginForm = () => {
     const {
       control,
       handleSubmit,
       formState: { errors },
     } = useForm<FormData>({
       defaultValues: {
         email: '',
         password: '',
       },
     })

     const onSubmit = (data: FormData) => console.log(data)

     return (
       <View>
         <Controller
           control={control}
           name="email"
           render={({ field: { onChange, onBlur, value } }) => (
             <TextField
               label="Email"
               onBlur={onBlur}
               onChangeText={onChange}
               value={value}
               placeholder="Enter your email"
               keyboardType="email-address"
               autoCapitalize="none"
               status={errors.email ? 'error' : 'default'}
               helperText={errors.email?.message}
             />
           )}
         />
         <Controller
           control={control}
           name="password"
           render={({ field: { onChange, onBlur, value } }) => (
             <TextField
               label="Password"
               onBlur={onBlur}
               onChangeText={onChange}
               value={value}
               placeholder="Enter your password"
               secureTextEntry
               status={errors.password ? 'error' : 'default'}
               helperText={errors.password?.message}
             />
           )}
         />
         <Button title="Submit" onPress={handleSubmit(onSubmit)} />
       </View>
     )
   }
   ```

## Zod: Type-Safe Schema Validation

[Zod](https://zod.dev/) is a TypeScript-first schema declaration and validation library. It allows you to define your data shapes with a concise API, and then validate data against those schemas, providing excellent type inference and robust error reporting.

### Key Features

* **TypeScript-first:** Provides powerful type inference, ensuring your forms are type-safe from definition to submission.
* **Concise API:** Easy to define complex validation schemas.
* **Runtime Validation:** Validates data at runtime, catching errors early.
* **Customizable Errors:** Full control over error messages.

### Basic Usage

1. **Define Your Schema:**
   ```typescript theme={null}
   import { z } from 'zod'

   export const loginSchema = z.object({
     email: z.string().email("Invalid email address"),
     password: z.string().min(6, "Password must be at least 6 characters long"),
   })

   // Infer the TypeScript type from the schema
   export type LoginFormData = z.infer<typeof loginSchema>
   ```
2. **Integrate with React Hook Form:** Use the `resolver` option with `@hookform/resolvers/zod`.
   ```typescript theme={null}
   import { useForm, Controller } from 'react-hook-form'
   import { zodResolver } from '@hookform/resolvers/zod'
   import { loginSchema, LoginFormData } from './loginSchema' // Your Zod schema
   import { TextField } from '@/../components/TextField'
   import { Button, View } from 'react-native'

   export const LoginFormWithValidation = () => {
     const {
       control,
       handleSubmit,
       formState: { errors },
     } = useForm<LoginFormData>({
       resolver: zodResolver(loginSchema), // Integrate Zod resolver
       defaultValues: {
         email: '',
         password: '',
       },
     })

     const onSubmit = (data: LoginFormData) => {
       console.log('Form submitted:', data)
       // Handle login logic here
     }

     return (
       <View>
         <Controller
           control={control}
           name="email"
           render={({ field: { onChange, onBlur, value } }) => (
             <TextField
               label="Email"
               onBlur={onBlur}
               onChangeText={onChange}
               value={value}
               placeholder="Enter your email"
               keyboardType="email-address"
               autoCapitalize="none"
               status={errors.email ? 'error' : 'default'}
               helperText={errors.email?.message}
             />
           )}
         />
         <Controller
           control={control}
           name="password"
           render={({ field: { onChange, onBlur, value } }) => (
             <TextField
               label="Password"
               onBlur={onBlur}
               onChangeText={onChange}
               value={value}
               placeholder="Enter your password"
               secureTextEntry
               status={errors.password ? 'error' : 'default'}
               helperText={errors.password?.message}
             />
           )}
         />
         <Button title="Submit" onPress={handleSubmit(onSubmit)} />
       </View>
     )
   }
   ```

## Best Practices

* **Centralize Schemas:** Define your Zod schemas in a dedicated `schemas/` directory or alongside your form components for easy access and reusability.
* **Custom Components:** Create reusable form input components (like `TextField` above) that integrate seamlessly with `Controller` from React Hook Form. This abstracts away the `field` props and provides a cleaner API.
* **Error Display:** Clearly display validation errors to the user using the `formState.errors` object.
* **Type Inference:** Always infer your form data types directly from your Zod schemas (`z.infer<typeof yourSchema>`) to ensure maximum type safety.

## Resources

* **React Hook Form Documentation:** [https://react-hook-form.com/](https://react-hook-form.com/)
* **Zod Documentation:** [https://zod.dev/](https://zod.dev/)
* **React Hook Form Resolvers:** [https://react-hook-form.com/docs/useform#resolver](https://react-hook-form.com/docs/useform#resolver)
* **Shipnative Components:** `apps/app/app/components/TextField.tsx` (for an example of a form input component)
