Agent skill

validating-forms

Teaches client and server-side form validation patterns in React 19 with Server Actions. Use when implementing form validation, input checking, or error handling.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/validating-forms

SKILL.md

Form Validation Patterns

React 19 forms require validation on both client and server.

Client-Side Validation

Use HTML5 validation + custom logic:

javascript
<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:

javascript
'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

javascript
'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:

javascript
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

Didn't find tool you were looking for?

Be as detailed as possible for better results