# Remix Forms Documentation

## Overview

Remix Forms is a full-stack form library for React Router v7 (formerly for Remix) that provides end-to-end type-safe forms with comprehensive features for modern web applications.

**Official Website**: https://remix-forms.seasoned.cc/  
**GitHub Repository**: https://github.com/seasonedcc/remix-forms  
**NPM Package**: remix-forms

## Key Features

- **End-to-end type safety** - Write your schema once and derive everything else
- **Client and server-side validation** - Validate everything both on the client and server
- **Accessibility support** - Built-in a11y features
- **Pending UI** - Automatic loading states
- **Focus management** - Smart focus handling
- **Single source of truth** - Schema-driven approach
- **Autocomplete** - Full TypeScript autocomplete support
- **Zero boilerplate** - Minimal code for maximum functionality

## Installation

```bash
npm install remix-forms
```

### Peer Dependencies

Make sure you have the following dependencies installed:
- React Router v7
- React
- Zod (for schema validation)

## Migration Note

⚠️ **Important**: Remix Forms v3 removed support for Remix and React Router v6. Before upgrading, you need to upgrade your app to React Router v7. If you can't upgrade, use Remix Forms 2.3.0 which remains stable for React Router v6 and Remix.

## Basic Usage

### 1. Define Your Schema

```typescript
import { z } from 'zod'

const schema = z.object({
  firstName: z.string().min(1, "First name is required"),
  email: z.string().min(1, "Email is required").email("Invalid email"),
  howDidYouFindUs: z.enum(['aFriend', 'google', 'other'])
})
```

### 2. Create Server Action

```typescript
import { formAction } from 'remix-forms'

export const action = async ({ request }) =>
  formAction({
    request,
    schema,
    mutation: async (values) => {
      // Your server-side logic here
      // Save to database, send emails, etc.
      return values
    },
    successPath: '/success', // Redirect on success
  })
```

### 3. Create Form Component

```typescript
import { SchemaForm } from 'remix-forms'

export default function ContactForm() {
  return <SchemaForm schema={schema} />
}
```

## Advanced Usage

### Custom Form UI

While `SchemaForm` provides automatic form generation, you can customize the UI:

```typescript
import { Form } from 'remix-forms'

export default function CustomForm() {
  return (
    <Form schema={schema}>
      {({ Field, Button, Errors }) => (
        <>
          <Field name="firstName">
            {({ Label, Input, Errors }) => (
              <div>
                <Label />
                <Input className="custom-input" />
                <Errors />
              </div>
            )}
          </Field>
          
          <Field name="email">
            {({ Label, Input, Errors }) => (
              <div>
                <Label />
                <Input type="email" />
                <Errors />
              </div>
            )}
          </Field>
          
          <Field name="howDidYouFindUs">
            {({ Label, Select, Errors }) => (
              <div>
                <Label />
                <Select>
                  <option value="">Select...</option>
                  <option value="aFriend">A Friend</option>
                  <option value="google">Google</option>
                  <option value="other">Other</option>
                </Select>
                <Errors />
              </div>
            )}
          </Field>
          
          <Button>Submit</Button>
        </>
      )}
    </Form>
  )
}
```

### Custom Validation Messages

```typescript
const schema = z.object({
  age: z
    .number()
    .min(18, "You must be at least 18 years old")
    .max(100, "Please enter a valid age"),
  password: z
    .string()
    .min(8, "Password must be at least 8 characters")
    .regex(/[A-Z]/, "Password must contain at least one uppercase letter")
    .regex(/[0-9]/, "Password must contain at least one number"),
})
```

### File Uploads

```typescript
const schema = z.object({
  name: z.string().min(1),
  avatar: z.instanceof(File).optional(),
})

export const action = async ({ request }) =>
  formAction({
    request,
    schema,
    mutation: async (values) => {
      if (values.avatar) {
        // Handle file upload
        const formData = new FormData()
        formData.append('file', values.avatar)
        // Upload to storage service
      }
      return values
    },
  })
```

### Conditional Fields

```typescript
const schema = z.object({
  hasAccount: z.boolean(),
  username: z.string().optional(),
  password: z.string().optional(),
}).refine(
  (data) => {
    if (data.hasAccount) {
      return data.username && data.password
    }
    return true
  },
  {
    message: "Username and password are required when you have an account",
    path: ["username"],
  }
)
```

## API Reference

### formAction

Handles form submission on the server:

```typescript
formAction({
  request: Request,
  schema: ZodSchema,
  mutation: async (values) => any,
  successPath?: string,
  errorPath?: string,
})
```

### SchemaForm

Auto-generates form from schema:

```typescript
<SchemaForm 
  schema={schema}
  values={initialValues}
  labels={{ 
    firstName: "Your First Name",
    email: "Email Address" 
  }}
  placeholders={{
    email: "john@example.com"
  }}
  options={{
    howDidYouFindUs: [
      { label: "From a Friend", value: "aFriend" },
      { label: "Google Search", value: "google" },
    ]
  }}
/>
```

### Form Component

For custom UI implementations:

```typescript
<Form schema={schema}>
  {({ Field, Button, Errors, state }) => (
    // Your custom form UI
  )}
</Form>
```

### Field Component

Individual field renderer:

```typescript
<Field name="fieldName">
  {({ Label, Input, Errors, props }) => (
    // Your custom field UI
  )}
</Field>
```

## Features in Detail

### Server-Side Validation

All validation runs on both client and server, ensuring data integrity even when JavaScript is disabled:

```typescript
export const action = async ({ request }) => {
  const result = await formAction({
    request,
    schema,
    mutation: async (values) => {
      // This only runs if validation passes
      return await saveToDatabase(values)
    },
  })
  
  // Handle validation errors
  if (!result.success) {
    return json({ errors: result.errors })
  }
  
  return redirect('/success')
}
```

### Progressive Enhancement

Forms work without JavaScript by default:

```typescript
// This form works with or without JavaScript
<SchemaForm 
  schema={schema} 
  method="post"
  action="/contact"
/>
```

### Type Safety

Full TypeScript support with inferred types:

```typescript
// Types are automatically inferred from schema
type FormData = z.infer<typeof schema>

const mutation = async (values: FormData) => {
  // values is fully typed
  console.log(values.firstName) // string
  console.log(values.email) // string
}
```

### Error Handling

Built-in error display and management:

```typescript
<Form schema={schema}>
  {({ Errors, Field }) => (
    <>
      <Errors /> {/* Global errors */}
      <Field name="email">
        {({ Errors }) => <Errors />} {/* Field-specific errors */}
      </Field>
    </>
  )}
</Form>
```

### Loading States

Automatic pending UI:

```typescript
<Form schema={schema}>
  {({ Button, state }) => (
    <Button disabled={state.submitting}>
      {state.submitting ? 'Submitting...' : 'Submit'}
    </Button>
  )}
</Form>
```

## Best Practices

1. **Keep schemas simple** - Complex validation logic should be in refinements
2. **Use server mutations** - Always validate and process on the server
3. **Provide clear error messages** - Help users understand what went wrong
4. **Test without JavaScript** - Ensure forms work with JS disabled
5. **Leverage type safety** - Let TypeScript catch errors at compile time

## Development

### Setup

```bash
# Clone repository
git clone https://github.com/seasonedcc/remix-forms.git

# Install dependencies
npm install

# Run development server
npm run dev
```

### Testing

```bash
# Install Playwright
npx playwright install

# Run tests
npm run test
```

### Scripts

- `npm run lint` - Check code style
- `npm run lint-fix` - Fix code style issues
- `npm run tsc` - Type check
- `npm run test` - Run tests

## Troubleshooting

### Node Version
Recommended to use Node 16 due to Turborepo compatibility issues with Node 18.

### React Router v7 Migration
If upgrading from v2 to v3, first upgrade your app to React Router v7 before updating remix-forms.

## Resources

- [Official Documentation](https://remix-forms.seasoned.cc/)
- [GitHub Repository](https://github.com/seasonedcc/remix-forms)
- [NPM Package](https://www.npmjs.com/package/remix-forms)
- [Examples](https://github.com/seasonedcc/remix-forms-site)
- [Remix Conf 2022 Presentation](https://remix-forms.seasoned.cc/conf/)

## Community

- Report issues on [GitHub Issues](https://github.com/seasonedcc/remix-forms/issues)
- Check [Releases](https://github.com/seasonedcc/remix-forms/releases) for updates
- Developed by [Seasoned](https://github.com/seasonedcc)