agentleFS
NikoxkxNikoxkx/Agent-Skills/skills/web-development/form-validator/SKILL.md

form-validator

Skill1 starsChanged 5 months agoApache-2.0View on GitHub

Implements client-side and server-side form validation with accessible error messaging. Use when adding validation to any HTML or React form.

  • Sends data out

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

Show its rules and text

We split this skill into the rules it gives an agent

14 rules. About 0 are common, 9 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈9

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use .refine() for cross-field rules.

    line 43
  2. Very specific:

    Add .transform() for sanitization when safe.

    line 44
  3. Distinctive:

    Document the chosen strategy and why.

    line 50
  4. Very specific:

    Every invalid field gets aria-invalid="true".

    line 53
  5. Distinctive:

    Never rely on color alone.

    line 56
  6. Distinctive:

    Always re-validate with the same schema.

    line 74
  7. Distinctive:

    Never trust client-only validation.

    line 76
  8. Very specific:

    Server returns field errors after submit: Use setError(field, { type: 'server', message: 'Taken' }) for each field.

    line 162
  9. Very specific:

    File validation: Check file.size and file.type client-side, but always re-validate on server (never trust client file metadata).

    line 164
  10. Distinctive:

    Password managers: Never disable autocomplete on login/registration fields.

    line 166
  11. Distinctive:

    Error message clarity: Write messages that tell the user what to do, not just what is wrong ("Enter a valid email" vs "Invalid email …

    line 167
  12. Distinctive:

    Test keyboard navigation and screen reader (VoiceOver/NVDA) — errors are announced when they appear.

    line 173
  13. Distinctive:

    Run axe DevTools on the form in error state — no violations related to forms or ARIA.

    line 174
  14. Distinctive:

    Test password mismatch, file too large, etc.

    line 176

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Overview

Implements robust, accessible form validation that works on both client and server. The skill produces validation schemas (Zod recommended), real-time and submit-time validation strategies, accessible error display patterns (aria-invalid, aria-describedby), common field validators (email, phone, password strength, date ranges, file uploads), and full integration examples with React Hook Form + Zod or vanilla HTML forms.

When to Use This Skill

  • Building or improving any form (login, registration, checkout, settings, multi-step wizards).
  • The user mentions "form validation", "validate input", "error messages", or provides a form description.
  • You need both client-side (UX) and server-side (security) validation.
  • Ensuring WCAG-compliant error presentation.

Prerequisites

  • Form framework decided (plain HTML + JS, React, React Hook Form, Formik, etc.).
  • Validation library: zod (strongly recommended), yup, or joi.
  • For React: react-hook-form + @hookform/resolvers is the modern standard.
  • Server-side endpoint that will receive the form data.
  • Accessibility knowledge (or the skill will guide).

Steps

  1. Identify all fields and validation rules:
    • Required/optional.
    • Type (text, email, number, date, file, etc.).
    • Format rules (min/max length, regex, range).
    • Cross-field validation (password confirmation, date start < end).
    • File-specific rules (type, size, count).
  2. Create a single source of truth schema (Zod):
    • Define once, use for client (via resolver) and server (parse).
    • Use .refine() for cross-field rules.
    • Add .transform() for sanitization when safe.
  3. Decide validation timing strategy:
    • Real-time (onChange/onBlur): Best UX for long forms. Show errors as user types or leaves field.
    • Submit-time only: Simpler for short forms or when you want to avoid error noise.
    • Hybrid: Validate on blur + full validation on submit.
    • Document the chosen strategy and why.
  4. Implement accessible error display:
    • Every invalid field gets aria-invalid="true".
    • Error message gets a unique id and is referenced via aria-describedby.
    • Error messages are placed immediately after the input (or in a live region for complex cases).
    • Never rely on color alone; use icon + text.
    • For screen readers, use role="alert" on error containers when appropriate.
  5. Common field patterns (include ready-to-use validators):
    • Email: z.string().email()
    • Phone: regex or libphonenumber-js
    • Password: length + complexity rules + confirmation match
    • Date ranges: custom refine
    • File upload: size, mime type, multiple files
    • URL, slug, username availability (async)
  6. React Hook Form + Zod integration (most common):
    • useForm({ resolver: zodResolver(schema) })
    • register with proper props.
    • FormProvider for nested or complex forms.
    • setError for server-side errors after submit.
  7. Server-side validation:
    • Always re-validate with the same schema.
    • Return field-specific errors in a consistent shape.
    • Never trust client-only validation.
  8. Output:
    • Zod schema file or inline.
    • Client form component (or vanilla JS + HTML).
    • Server handler snippet.
    • Example of error response shape.
    • Accessibility notes and test instructions.

Examples

Example 1: Registration Form (React + React Hook Form + Zod)

// schemas/registration.ts
import { z } from 'zod';

export const registrationSchema = z.object({
  email: z.string().email('Please enter a valid email address'),
  password: z.string()
    .min(8, 'Password must be at least 8 characters')
    .regex(/[A-Z]/, 'Must contain at least one uppercase letter')
    .regex(/[0-9]/, 'Must contain at least one number'),
  confirmPassword: z.string(),
  fullName: z.string().min(2).max(100),
  acceptTerms: z.boolean().refine(val => val === true, {
    message: 'You must accept the terms and conditions',
  }),
}).refine((data) => data.password === data.confirmPassword, {
  message: "Passwords don't match",
  path: ['confirmPassword'],
});

export type RegistrationInput = z.infer<typeof registrationSchema>;
// components/RegistrationForm.tsx
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { registrationSchema, type RegistrationInput } from '@/schemas/registration';

export function RegistrationForm() {
  const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<RegistrationInput>({
    resolver: zodResolver(registrationSchema),
    mode: 'onBlur',
  });

  const onSubmit = async (data: RegistrationInput) => {
    // Server call here — server will also validate
    const res = await fetch('/api/register', { method: 'POST', body: JSON.stringify(data) });
    // handle response...
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)} noValidate>
      <div>
        <label htmlFor="email">Email</label>
        <input
          id="email"
          type="email"
          {...register('email')}
          aria-invalid={!!errors.email}
          aria-describedby={errors.email ? 'email-error' : undefined}
          className={errors.email ? 'border-red-500' : ''}
        />
        {errors.email && (
          <p id="email-error" role="alert" className="text-red-600 text-sm mt-1">
            {errors.email.message}
          </p>
        )}
      </div>
      {/* more fields... */}
      <button type="submit" disabled={isSubmitting}>Create account</button>
    </form>
  );
}

Server-side validation snippet also provided.

Example 2: Vanilla HTML + JS form with the same schema logic (using Zod in browser via CDN or bundled).

Edge Cases & Error Handling

  • Async validation (username availability): Use useForm's validate or server-side only + debounced check. Show loading state on the field.
  • Server returns field errors after submit: Use setError(field, { type: 'server', message: 'Taken' }) for each field.
  • Very long forms / multi-step: Validate only the current step on "Next". Keep one schema or split into step schemas.
  • File validation: Check file.size and file.type client-side, but always re-validate on server (never trust client file metadata).
  • International phone numbers: Recommend libphonenumber-js or react-phone-number-input.
  • Password managers: Never disable autocomplete on login/registration fields.
  • Error message clarity: Write messages that tell the user what to do, not just what is wrong ("Enter a valid email" vs "Invalid email format").

Verification

  1. Fill the form with valid data → submits successfully.
  2. Submit with each invalid field one-by-one → correct, accessible error appears next to the field.
  3. Test keyboard navigation and screen reader (VoiceOver/NVDA) — errors are announced when they appear.
  4. Run axe DevTools on the form in error state — no violations related to forms or ARIA.
  5. Submit the same invalid data directly to the server endpoint (bypass client) — server rejects with proper 422 and field errors.
  6. Test password mismatch, file too large, etc.
  7. Success: Users can correct errors without confusion. Screen reader users understand problems. Server is protected. No validation bypass possible.

References

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.