forms

GitHub

规定前端表单开发规范,强制使用 React Hook Form 结合 Zod 进行类型推断与数据校验。涵盖基础模式、复杂组件控制、状态管理及错误处理,确保表单构建的一致性与健壮性。

.claude/skills/forms/SKILL.md trycompai/comp

Trigger Scenarios

构建表单界面 实现表单数据验证 处理表单提交逻辑

Install

npx skills add trycompai/comp --skill forms -g -y
More Options

Non-standard path

npx skills add https://github.com/trycompai/comp/tree/main/.claude/skills/forms -g -y

Use without installing

npx skills use trycompai/comp@forms

指定 Agent (Claude Code)

npx skills add trycompai/comp --skill forms -a claude-code -g -y

安装 repo 全部 skill

npx skills add trycompai/comp --all -g -y

预览 repo 内 skill

npx skills add trycompai/comp --list

SKILL.md

Frontmatter
{
    "name": "forms",
    "description": "Use when building forms - covers React Hook Form, Zod validation, and form patterns"
}

Source Cursor rule: .cursor/rules/forms.mdc. Original Cursor alwaysApply: false.

Forms: React Hook Form + Zod

All forms MUST use React Hook Form with Zod validation.

Basic Pattern

import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { Button, Input } from '@trycompai/design-system';

// 1. Define schema
const formSchema = z.object({
  email: z.string().email('Invalid email'),
  password: z.string().min(8, 'Min 8 characters'),
});

// 2. Infer type
type FormData = z.infer<typeof formSchema>;

// 3. Use in component
function MyForm() {
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
  } = useForm<FormData>({
    resolver: zodResolver(formSchema),
  });

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Input {...register('email')} />
      {errors.email && <p>{errors.email.message}</p>}
      
      <Button type="submit" loading={isSubmitting}>
        Submit
      </Button>
    </form>
  );
}

Zod Schema Patterns

const profileSchema = z.object({
  // Strings
  name: z.string().min(1, 'Required'),
  email: z.string().email(),
  website: z.string().url().optional(),
  
  // Numbers (coerce for inputs)
  age: z.coerce.number().int().min(0),
  price: z.coerce.number().positive(),
  
  // Arrays
  tags: z.array(z.string()).min(1),
  
  // Enums
  status: z.enum(['active', 'inactive']),
});

// Cross-field validation
const passwordSchema = z.object({
  password: z.string().min(8),
  confirmPassword: z.string(),
}).refine(d => d.password === d.confirmPassword, {
  message: "Passwords don't match",
  path: ['confirmPassword'],
});

Controller for Complex Components

import { Controller } from 'react-hook-form';
import { Select, SelectContent, SelectItem, SelectTrigger } from '@trycompai/design-system';

<Controller
  name="status"
  control={control}
  render={({ field }) => (
    <Select onValueChange={field.onChange} value={field.value}>
      <SelectTrigger>{field.value || 'Select...'}</SelectTrigger>
      <SelectContent>
        <SelectItem value="active">Active</SelectItem>
        <SelectItem value="inactive">Inactive</SelectItem>
      </SelectContent>
    </Select>
  )}
/>

Form State

const {
  register,
  handleSubmit,
  control,
  watch,           // Watch field values
  setValue,        // Set field programmatically
  reset,           // Reset form
  setError,        // Set error manually
  formState: {
    errors,        // Field errors
    isSubmitting,  // Submitting
    isValid,       // All valid
    isDirty,       // Modified
  },
} = useForm<FormData>({
  resolver: zodResolver(schema),
  mode: 'onChange', // Validate on change
});

Error Handling

const onSubmit = async (data: FormData) => {
  try {
    await submitToApi(data);
  } catch (error) {
    // Field-specific error
    setError('email', { message: 'Email taken' });
    // Or root error
    setError('root', { message: 'Something went wrong' });
  }
};

// Display root error
{errors.root && <p>{errors.root.message}</p>}

Dynamic Fields

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

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

{fields.map((field, index) => (
  <div key={field.id}>
    <Input {...register(`items.${index}.name`)} />
    <Button type="button" onClick={() => remove(index)}>Remove</Button>
  </div>
))}
<Button type="button" onClick={() => append({ name: '' })}>Add</Button>

Anti-Patterns

// ❌ useState for form fields
const [email, setEmail] = useState('');

// ❌ Manual validation
if (email.length < 5) setError('Too short');

// ❌ Missing button type (defaults to submit)
<Button onClick={handleCancel}>Cancel</Button>

// ✅ Correct
const { register } = useForm();
const schema = z.object({ email: z.string().min(5) });
<Button type="button" onClick={handleCancel}>Cancel</Button>

Version History

  • 0ccfcc2 Current 2026-09-27 10:24

Same Skill Collection

.agents/skills/audit-design-system/SKILL.md
.agents/skills/audit-hooks/SKILL.md
.agents/skills/audit-rbac/SKILL.md
.agents/skills/audit-tests/SKILL.md
.agents/skills/better-auth-best-practices/SKILL.md
.agents/skills/billing/SKILL.md
.agents/skills/code/SKILL.md
.agents/skills/cursor-usage/SKILL.md
.agents/skills/data/SKILL.md
.agents/skills/diagnose-generation-failure/SKILL.md
.agents/skills/forms/SKILL.md
.agents/skills/generate-mcp-server/SKILL.md
.agents/skills/infra/SKILL.md
.agents/skills/manage-openapi-overlays/SKILL.md
.agents/skills/new-feature-setup/SKILL.md
.agents/skills/production-readiness/SKILL.md
.agents/skills/prompt-engineering/SKILL.md
.agents/skills/speakeasy-context/SKILL.md
.agents/skills/stale-worktree-cleanup/SKILL.md
.agents/skills/trigger-advanced-tasks/SKILL.md
.agents/skills/trigger-basic/SKILL.md
.agents/skills/trigger-config/SKILL.md
.agents/skills/trigger-realtime/SKILL.md
.agents/skills/ui/SKILL.md
.claude/skills/api-endpoint-contract/SKILL.md
.claude/skills/audit-design-system/SKILL.md
.claude/skills/audit-hooks/SKILL.md
.claude/skills/audit-rbac/SKILL.md
.claude/skills/audit-tests/SKILL.md
.claude/skills/check-results-service/SKILL.md
.claude/skills/cleanup/SKILL.md
.claude/skills/code/SKILL.md
.claude/skills/cursor-usage/SKILL.md
.claude/skills/data/SKILL.md
.claude/skills/infra/SKILL.md
.claude/skills/new-feature-setup/SKILL.md
.claude/skills/production-readiness/SKILL.md
.claude/skills/prompt-engineering/SKILL.md
.claude/skills/security-review/SKILL.md
.claude/skills/stale-worktree-cleanup/SKILL.md
.claude/skills/trigger-advanced-tasks/SKILL.md
.claude/skills/trigger-basic/SKILL.md
.claude/skills/trigger-config/SKILL.md
.claude/skills/trigger-realtime/SKILL.md
.claude/skills/ui/SKILL.md
.agents/skills/essentials/SKILL.md
.agents/skills/prisma/SKILL.md
.agents/skills/trigger-scheduled-tasks/SKILL.md
.claude/skills/essentials/SKILL.md

Metadata

Files
0
Version
0ccfcc2
Hash
44562268
Indexed
2026-09-27 10:24

Home - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-27 23:59
浙ICP备14020137号-1