Token导航 LogoToken导航TokenDH.com
前端设计external-servicegithub未标认证来源可访问许可证需确认审计通过

react-formsReact 表单

Agent Skill

用于辅助前端页面、组件、样式和交互逻辑的开发与维护。它适合让 Agent 生成或审查 React、Next.js、Vue、Tailwind、CSS 等相关代码,整理组件结构,或定位布局和性能问题。使用时需要结合项目现有设计系统、路由和构建方式,避免只生成孤立片段;涉及页面改动时,应配合本地预览和构建检查确认视觉效果。

总安装

692

周安装

28

GitHub Stars

12

下载量

217
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:react-forms(React 表单)
来源仓库:https://github.com/claude-dev-suite/claude-dev-suite
仓库路径:skills/react-forms
安装命令:
npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill react-forms
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill react-forms

简介

专注于 React 表单开发与验证的技能。

  • 适用于处理输入校验、错误提示和数据收集。react-forms 属于前端设计类 Skill,可作为该场景下的辅助能力补充。
  • 支持多种 UI 库如 shadcn/ui 的表单组件集成。
  • 通过 GitHub 安装,需适配项目现有样式系统。
  • 建议在本地测试所有边界情况,确保用户体验一致。

SKILL.md

React Forms

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: react topic: forms for comprehensive documentation on React form patterns and validation strategies.
Full Reference: See advanced.md for Server Actions, Multi-Step Forms, Dependent Fields, Auto-Save, Validation Patterns, and Accessibility.

Controlled vs Uncontrolled

Controlled Forms

React state controls the input:

function ControlledForm() {
  const [formData, setFormData] = useState({
    email: '',
    password: '',
  });
  const [errors, setErrors] = useState<Record<string, string>>({});

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));

    if (errors[name]) {
      setErrors(prev => ({ ...prev, [name]: '' }));
    }
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();

    const newErrors: Record<string, string> = {};
    if (!formData.email) newErrors.email = 'Email required';
    if (!formData.password) newErrors.password = 'Password required';

    if (Object.keys(newErrors).length > 0) {
      setErrors(newErrors);
      return;
    }

    console.log('Submitting:', formData);
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <input
          name="email"
          type="email"
          value={formData.email}
          onChange={handleChange}
        />
        {errors.email && <span className="error">{errors.email}</span>}
      </div>

      <div>
        <input
          name="password"
          type="password"
          value={formData.password}
          onChange={handleChange}
        />
        {errors.password && <span className="error">{errors.password}</span>}
      </div>

      <button type="submit">Submit</button>
    </form>
  );
}

Uncontrolled Forms (useRef)

DOM controls the input:

function UncontrolledForm() {
  const emailRef = useRef<HTMLInputElement>(null);
  const passwordRef = useRef<HTMLInputElement>(null);

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();

    const data = {
      email: emailRef.current?.value,
      password: passwordRef.current?.value,
    };

    console.log('Submitting:', data);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input ref={emailRef} name="email" type="email" />
      <input ref={passwordRef} name="password" type="password" />
      <button type="submit">Submit</button>
    </form>
  );
}

FormData API (Uncontrolled)

function FormDataForm() {
  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget);

    const data = {
      email: formData.get('email') as string,
      password: formData.get('password') as string,
    };

    console.log('Submitting:', data);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="email" type="email" required />
      <input name="password" type="password" required />
      <button type="submit">Submit</button>
    </form>
  );
}

React Hook Form

Most popular form library - uncontrolled with great DX:

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

const schema = z.object({
  email: z.string().email('Invalid email'),
  password: z.string().min(8, 'Password must be at least 8 characters'),
  confirmPassword: z.string(),
}).refine(data => data.password === data.confirmPassword, {
  message: 'Passwords must match',
  path: ['confirmPassword'],
});

type FormData = z.infer<typeof schema>;

function SignUpForm() {
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
    reset,
  } = useForm<FormData>({
    resolver: zodResolver(schema),
    defaultValues: { email: '', password: '', confirmPassword: '' },
  });

  const onSubmit = async (data: FormData) => {
    try {
      await signUp(data);
      reset();
    } catch (error) {
      console.error('Sign up failed:', error);
    }
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <input {...register('email')} type="email" placeholder="Email" />
        {errors.email && <span className="error">{errors.email.message}</span>}
      </div>

      <div>
        <input {...register('password')} type="password" placeholder="Password" />
        {errors.password && <span className="error">{errors.password.message}</span>}
      </div>

      <div>
        <input {...register('confirmPassword')} type="password" placeholder="Confirm Password" />
        {errors.confirmPassword && <span className="error">{errors.confirmPassword.message}</span>}
      </div>

      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? 'Signing up...' : 'Sign Up'}
      </button>
    </form>
  );
}

Form Arrays

import { useFieldArray, useForm } from 'react-hook-form';

interface OrderForm {
  items: { productId: string; quantity: number }[];
  notes: string;
}

function OrderForm() {
  const { register, control, handleSubmit } = useForm<OrderForm>({
    defaultValues: {
      items: [{ productId: '', quantity: 1 }],
      notes: '',
    },
  });

  const { fields, append, remove } = useFieldArray({
    control,
    name: 'items',
  });

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {fields.map((field, index) => (
        <div key={field.id} className="flex gap-2">
          <select {...register(`items.${index}.productId`)}>
            <option value="">Select product</option>
            {products.map(p => (
              <option key={p.id} value={p.id}>{p.name}</option>
            ))}
          </select>

          <input
            {...register(`items.${index}.quantity`, { valueAsNumber: true })}
            type="number"
            min="1"
          />

          <button type="button" onClick={() => remove(index)}>
            Remove
          </button>
        </div>
      ))}

      <button type="button" onClick={() => append({ productId: '', quantity: 1 })}>
        Add Item
      </button>

      <textarea {...register('notes')} placeholder="Notes" />
      <button type="submit">Submit Order</button>
    </form>
  );
}

Controlled Components with RHF

import { Controller, useForm } from 'react-hook-form';
import { DatePicker } from '@/components/date-picker';

function EventForm() {
  const { control, handleSubmit } = useForm();

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="date"
        control={control}
        rules={{ required: 'Date is required' }}
        render={({ field, fieldState }) => (
          <div>
            <DatePicker
              value={field.value}
              onChange={field.onChange}
            />
            {fieldState.error && (
              <span className="error">{fieldState.error.message}</span>
            )}
          </div>
        )}
      />

      <button type="submit">Create Event</button>
    </form>
  );
}

Best Practices

DoDon't
Use React Hook Form for complex formsManage all form state manually
Use Zod/Yup for validationWrite validation from scratch
Show inline errorsShow all errors at once
Use aria-* attributesForget accessibility
Debounce expensive validationsValidate async on every keystroke
  • ✅ Use controlled inputs when you need real-time validation
  • ✅ Use uncontrolled inputs (RHF) for better performance
  • ✅ Validate on blur for better UX
  • ✅ Show loading state during submission
  • ❌ Don't disable submit button on empty form
  • ❌ Don't clear form on error
  • ❌ Don't show errors before user interaction

When NOT to Use This Skill

  • React Hook Form with Zod schemas - Use react-hook-form skill for detailed patterns
  • React 19 Server Actions forms - Use react-19 skill for useActionState and useFormStatus
  • Simple input handling - Use react skill for basic controlled/uncontrolled inputs
  • Form libraries other than RHF - Follow library-specific documentation

Anti-Patterns

Anti-PatternProblemSolution
Managing all form state manuallyBoilerplate, bugsUse React Hook Form
Not validating user inputSecurity/UX issuesUse Zod validation schema
Showing all errors on mountBad UXValidate on blur or submit
Disabling submit on empty formPrevents validation messagesAllow submit, show errors
Clearing form on validation errorUser loses dataKeep form data, show errors
Not showing loading stateConfusing UXShow loading during submission
Missing accessibility attributesNot accessibleAdd aria labels and roles
Validating async on every keystrokePerformance issuesDebounce async validation

Quick Troubleshooting

IssueLikely CauseFix
Form not submittingMissing onSubmit or actionAdd onSubmit handler to form
Validation not workingSchema not appliedCheck resolver in useForm
Input not updatingNot controlled properlyEnsure value and onChange are set
Errors not showingMissing FormMessageAdd FormMessage component
Submit button always disabledWrong isPending checkUse formState.isSubmitting
Values not resettingNot calling reset()Call form.reset() after success
Async validation too frequentNo debounceDebounce validation function

Reference Documentation

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

32.85%
按下载量换算71

Claude

28.94%
按下载量换算63

Cursor

18.85%
按下载量换算41

Gemini CLI

10.42%
按下载量换算23

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

external-service

该 Skill 可能调用第三方服务、云服务或外部模型 API,使用前需要确认账号、额度、数据发送范围和服务条款。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills