← Back to list

validating-forms
by djankies
⭐ 0🍴 0📅 Nov 25, 2025
SKILL.md
name: validating-forms description: Teaches client and server-side form validation patterns in React 19 with Server Actions. Use when implementing form validation, input checking, or error handling. allowed-tools: Read, Write, Edit version: 1.0.0
Form Validation Patterns
React 19 forms require validation on both client and server.
Client-Side Validation
Use HTML5 validation + custom logic:
<form action={submitForm}>
<input
name="email"
type="email"
required
pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$"
/>
<input
name="age"
type="number"
min="18"
max="120"
required
/>
<button type="submit">Submit</button>
</form>
Server-Side Validation (Required)
Always validate on server - client validation can be bypassed:
'use server';
import { z } from 'zod';
const schema = z.object({
email: z.string().email('Invalid email'),
age: z.number().min(18, 'Must be 18+').max(120),
password: z.string().min(8, 'Password must be 8+ characters'),
});
export async function registerUser(previousState, formData) {
const data = {
email: formData.get('email'),
age: Number(formData.get('age')),
password: formData.get('password'),
};
const result = schema.safeParse(data);
if (!result.success) {
return {
errors: result.error.flatten().fieldErrors,
};
}
try {
const user = await db.users.create({ data: result.data });
return { success: true, userId: user.id };
} catch (error) {
if (error.code === 'P2002') {
return { errors: { email: ['Email already exists'] } };
}
return { error: 'Registration failed' };
}
}
Display Errors
'use client';
import { useActionState } from 'react';
import { registerUser } from './actions';
export default function RegisterForm() {
const [state, formAction, isPending] = useActionState(registerUser, null);
return (
<form action={formAction}>
<div>
<input name="email" type="email" required />
{state?.errors?.email && (
<span className="error">{state.errors.email[0]}</span>
)}
</div>
<div>
<input name="age" type="number" required />
{state?.errors?.age && (
<span className="error">{state.errors.age[0]}</span>
)}
</div>
<div>
<input name="password" type="password" required />
{state?.errors?.password && (
<span className="error">{state.errors.password[0]}</span>
)}
</div>
<button type="submit" disabled={isPending}>
{isPending ? 'Registering...' : 'Register'}
</button>
{state?.error && <p className="error">{state.error}</p>}
{state?.success && <p>Registration successful!</p>}
</form>
);
}
Validation Libraries
Recommended: Zod for type-safe validation:
import { z } from 'zod';
const schema = z.object({
email: z.string().email(),
password: z.string().min(8),
confirmPassword: z.string(),
}).refine(data => data.password === data.confirmPassword, {
message: "Passwords don't match",
path: ['confirmPassword'],
});
For comprehensive validation patterns, see: research/react-19-comprehensive.md.
Related Skills
Zod v4 Validation:
- handling-zod-errors skill from the zod-4 plugin - Advanced error customization with unified error API, custom messages, and error formatting for better user feedback
- writing-zod-transformations skill from the zod-4 plugin - Built-in string transformations (trim, toLowerCase) for normalizing user input before validation
Score
Total Score
60/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
Reviews
💬
Reviews coming soon