← Back to list
1. Schema (

create-form
by tech-with-seth
React Router 7 starter with Polar.sh, BetterAuth, Prisma, and Tailwind
⭐ 1🍴 0📅 Jan 24, 2026
SKILL.md
name: create-form description: Set up hybrid client/server validated forms with Zod and React Hook Form. Use when creating forms with validation.
Create Form
When to Use
- Creating any form with validation
- User asks to "add a form" or "create a form"
Critical Rule
// CORRECT - Use <form> with manual fetcher.submit()
<form onSubmit={handleSubmit(onSubmit)}>
// WRONG - Causes submission conflicts
<fetcher.Form onSubmit={handleSubmit(onSubmit)}>
Core Pattern
- Same Zod schema on client and server
- Client: Instant feedback with React Hook Form
- Server: Security with
validateFormData() - Auto error sync: Server errors populate form fields
Quick Start
1. Schema (app/lib/validations.ts)
import { z } from 'zod';
export const contactFormSchema = z.object({
name: z.string().min(1, 'Name is required'),
email: z.string().email('Invalid email'),
});
export type ContactFormData = z.infer<typeof contactFormSchema>;
2. Server Action
import { validateFormData } from '~/lib/form-validation.server';
import { zodResolver } from '@hookform/resolvers/zod';
export async function action({ request }: Route.ActionArgs) {
const formData = await request.formData();
const { data, errors } = await validateFormData<ContactFormData>(
formData,
zodResolver(contactFormSchema)
);
if (errors) return data({ errors }, { status: 400 });
await processData(data!);
return redirect('/success');
}
3. Client Form
import { useFetcher } from 'react-router';
import { useValidatedForm } from '~/lib/form-hooks';
export default function ContactPage() {
const fetcher = useFetcher();
const { register, handleSubmit, formState: { errors } } = useValidatedForm({
resolver: zodResolver(contactFormSchema),
errors: fetcher.data?.errors,
});
const onSubmit = (data: ContactFormData) => {
const formData = new FormData();
formData.append('name', data.name);
fetcher.submit(formData, { method: 'POST' });
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<TextInput {...register('name')} error={errors.name?.message} />
<Button type="submit">Submit</Button>
</form>
);
}
Checklist
- Define Zod schema in
app/lib/validations.ts - Add server action with
validateFormData() - Use
useValidatedFormhook in component - Use
<form>(not<fetcher.Form>) withhandleSubmit
Templates
Full Reference
See .github/instructions/form-validation.instructions.md for:
- Field-level vs form-level errors
- Conditional validation
- File uploads
- Complex schema patterns
Score
Total Score
65/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
✓最近の活動
1ヶ月以内に更新
+10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
✓タグ
1つ以上のタグが設定されている
+5
Reviews
💬
Reviews coming soon

